diff --git a/CMakeLists.txt b/CMakeLists.txt index af29ecfa..7ed97003 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,8 +3,6 @@ project(.) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED on) - -set(CMAKE_C_STANDARD 17) set(CMAKE_C_STANDARD_REQUIRED on) add_compile_options(-Wall -g -O3 -fPIC) diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index bbf58558..b32e4d47 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -3,11 +3,9 @@ project(.) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED on) - -set(CMAKE_C_STANDARD 17) set(CMAKE_C_STANDARD_REQUIRED on) -add_compile_options(-Wall -g -O3) +add_compile_options(-Wall -g -O3 -fPIC) add_subdirectory("../" "./Dynamo") diff --git a/demos/init.cpp b/demos/init.cpp index 84b41540..d7f94634 100644 --- a/demos/init.cpp +++ b/demos/init.cpp @@ -1,15 +1,15 @@ #include int main() { - Dynamo::ApplicationConfiguration config; - config.title = "Hello, world!"; - config.width = 640; - config.height = 480; - config.asset_directory = "../assets/"; + Dynamo::ApplicationSettings settings; + settings.title = "Hello, world!"; + settings.window_width = 640; + settings.window_height = 480; + settings.root_asset_directory = "../assets/"; - Dynamo::Application app(config); + Dynamo::Application app(settings); while (app.is_running()) { - app.run(); + app.update(); } return 0; } diff --git a/src/Application.cpp b/src/Application.cpp new file mode 100644 index 00000000..7885058c --- /dev/null +++ b/src/Application.cpp @@ -0,0 +1,28 @@ +#include "Application.hpp" + +namespace Dynamo { + Application::Application(const ApplicationSettings &settings) { + _display = std::make_unique(settings.title, + settings.window_width, + settings.window_height); + _jukebox = std::make_unique(); + } + + bool Application::is_running() const { return _display->is_open(); } + + Display &Application::get_display() { return *_display; } + + Input &Application::get_input() { return _display->get_input(); } + + Clock &Application::get_clock() { return _clock; } + + Sound::Jukebox &Application::get_jukebox() { return *_jukebox; } + + void Application::update() { + // Update subsystems + _display->get_input().poll(); + + // Tick + _clock.tick(); + } +} // namespace Dynamo \ No newline at end of file diff --git a/src/Application.hpp b/src/Application.hpp new file mode 100644 index 00000000..b76f3ef3 --- /dev/null +++ b/src/Application.hpp @@ -0,0 +1,107 @@ +#pragma once + +#include +#include + +#include "./Sound/Jukebox.hpp" +#include "Clock.hpp" +#include "Display.hpp" + +namespace Dynamo { + /** + * @brief Application setup options. + * + */ + struct ApplicationSettings { + /** + * @brief Application title. + * + */ + std::string title; + + /** + * @brief Width of the display window. + * + */ + unsigned window_width; + + /** + * @brief Height of the display window. + * + */ + unsigned window_height; + + /** + * @brief Root asset directory. + * + */ + std::string root_asset_directory; + }; + + /** + * @brief Dynamo Application. + * + */ + class Application { + std::unique_ptr _display; + std::unique_ptr _jukebox; + + Clock _clock; + + public: + /** + * @brief Initialize a new Application. + * + * @param settings + */ + Application(const ApplicationSettings &settings); + + /** + * @brief Check if the application is running. + * + * @return true + * @return false + */ + bool is_running() const; + + /** + * @brief Get the display. + * + * @return Display& + */ + Display &get_display(); + + /** + * @brief Get the input handler. + * + * @return Input& + */ + Input &get_input(); + + /** + * @brief Get the clock. + * + * @return Clock& + */ + Clock &get_clock(); + + /** + * @brief Get the audio engine. + * + * @return Sound::Jukebox& + */ + Sound::Jukebox &get_jukebox(); + + /** + * @brief Update the application state. + * + */ + void update(); + }; + + /** + * @brief Application reference. + * + */ + using ApplicationRef = std::reference_wrapper; +} // namespace Dynamo \ No newline at end of file diff --git a/src/Application/Application.cpp b/src/Application/Application.cpp deleted file mode 100644 index 2fdc7c24..00000000 --- a/src/Application/Application.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "Application.hpp" - -namespace Dynamo { - Application::Application(ApplicationConfiguration config) { - // Initialize GLFW - if (!glfwInit()) { - Log::error("Failed to initialize GLFW."); - } - - // Core submodules - _assets = std::make_unique(config.asset_directory); - _display = std::make_unique( - config.width, - config.height, - config.title, - config.flags & ApplicationFlag::FullScreen, - config.flags & ApplicationFlag::VSync); - _input = std::make_unique(*_display); - _clock = std::make_unique(); - - // Graphics and sound submodules - _renderer = std::make_unique(*_display); - _jukebox = std::make_unique(); - - // Seed the random number generator - Random::seed(_clock->epoch().count()); - } - - Application::~Application() { glfwTerminate(); } - - AssetCache &Application::get_assets() { return *_assets; } - - Core Application::get_core() { return {*_display, *_input, *_clock}; } - - Graphics::Vulkan::Renderer &Application::get_renderer() { - return *_renderer; - } - - Sound::Jukebox &Application::get_jukebox() { return *_jukebox; } - - b8 Application::is_running() { return !_display->is_closed(); } - - void Application::run() { - // TODO: Use semi-fixed timestep to update game logic - // (https://gafferongames.com/post/fix_your_timestep/) - _input->poll(); - _clock->tick(); - - // Process audio and graphics in parallel - _threads.submit([this]() { _jukebox->update(); }); - _threads.submit([this]() { _renderer->refresh(); }); - _threads.wait_all(); - } -} // namespace Dynamo \ No newline at end of file diff --git a/src/Application/Application.hpp b/src/Application/Application.hpp deleted file mode 100644 index 78f5bf65..00000000 --- a/src/Application/Application.hpp +++ /dev/null @@ -1,129 +0,0 @@ -#pragma once - -#include "../Asset/AssetCache.hpp" -#include "../Clock/Clock.hpp" -#include "../Core/Core.hpp" -#include "../Core/Display.hpp" -#include "../Core/Input.hpp" -#include "../Graphics/Renderer.hpp" -#include "../Graphics/Vulkan/Renderer.hpp" -#include "../Log/Log.hpp" -#include "../Sound/Jukebox.hpp" -#include "../Types.hpp" -#include "../Utils/Random.hpp" -#include "../Utils/ThreadPool.hpp" -#include "./ApplicationFlag.hpp" - -namespace Dynamo { - /** - * @brief Application startup configuration options. - * - */ - struct ApplicationConfiguration { - /** - * @brief Title of the display. - * - */ - std::string title; - - /** - * @brief Width of the display. - * - */ - u32 width; - - /** - * @brief Height of the display. - * - */ - u32 height; - - /** - * @brief Runtime settings. - * - */ - ApplicationFlag flags = ApplicationFlag::None; - - /** - * @brief Root asset directory. - * - */ - std::string asset_directory; - }; - - /** - * @brief Runtime synchronizes the game loop, rendering, sound, and scenes. - * - */ - class Application { - std::unique_ptr _assets; - std::unique_ptr _display; - std::unique_ptr _input; - std::unique_ptr _clock; - - std::unique_ptr _renderer; - std::unique_ptr _jukebox; - - ThreadPool _threads; - - public: - /** - * @brief Construct a new Application object. - * - * @param config Initialization options. - */ - Application(ApplicationConfiguration config); - - /** - * @brief Destroy the Application object. - * - * This will clean up the scenes and the GLFW instance. - * - */ - ~Application(); - - /** - * @brief Get the assets cache. - * - * @return AssetCache& - */ - AssetCache &get_assets(); - - /** - * @brief Get the core modules. - * - * @return const Core. - */ - Core get_core(); - - /** - * @brief Get a reference to the audio engine. - * - * @return Sound::Jukebox& - */ - Sound::Jukebox &get_jukebox(); - - /** - * @brief Get a reference to the rendering engine. - * - * TODO: Return Graphics::Renderer once Vulkan implementation is ready. - * - * @return Graphics::Renderer& - */ - Graphics::Vulkan::Renderer &get_renderer(); - - /** - * @brief Is the application still running? - * - * @return true - * @return false - */ - b8 is_running(); - - /** - * @brief Perform a single frame update. - * - */ - void run(); - }; -} // namespace Dynamo \ No newline at end of file diff --git a/src/Application/ApplicationFlag.hpp b/src/Application/ApplicationFlag.hpp deleted file mode 100644 index 055e6bab..00000000 --- a/src/Application/ApplicationFlag.hpp +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include "../Types.hpp" - -namespace Dynamo { - /** - * @brief Customizable flags for initializing the engine. - * - */ - enum class ApplicationFlag : u32 { - /** - * @brief None. - * - */ - None = 0, - - /** - * @brief Enable fullscreen mode. - * - */ - FullScreen = 1 << 0, - - /** - * @brief Enable vsync. - * - */ - VSync = 1 << 1 - }; - - /** - * @brief AND operator. - * - * @param lhs - * @param rhs - * @return u32 - */ - inline u32 operator&(ApplicationFlag lhs, ApplicationFlag rhs) { - return static_cast(lhs) & static_cast(rhs); - } - - /** - * @brief OR operator. - * - * @param lhs - * @param rhs - * @return ApplicationFlag - */ - inline ApplicationFlag operator|(ApplicationFlag lhs, ApplicationFlag rhs) { - return static_cast(static_cast(lhs) | - static_cast(rhs)); - } - - /** - * @brief OR operator in-place. - * - * @param lhs - * @param rhs - * @return ApplicationFlag - */ - inline ApplicationFlag operator|=(ApplicationFlag &lhs, - ApplicationFlag rhs) { - lhs = lhs | rhs; - return lhs; - } -} // namespace Dynamo \ No newline at end of file diff --git a/src/Asset/Asset.hpp b/src/Asset/Asset.hpp deleted file mode 100644 index b9043772..00000000 --- a/src/Asset/Asset.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include - -namespace Dynamo { - /** - * @brief Forward declaration of the asset cache. - * - */ - class AssetCache; - - /** - * @brief Asset handle. - * - * @tparam T Structure of the asset resource. - */ - template - class Asset { - std::shared_ptr _data; - - /** - * @brief Construct a new Asset object. - * - * @param data Heap allocated pointer to the asset resource. - */ - explicit Asset(const std::shared_ptr &data) : _data(data) {} - - public: - friend class AssetCache; - - /** - * @brief Dereference operator. - * - * @return T& - */ - inline T &operator*() { return *_data; } - - /** - * @brief Data pointer access operator. - * - * @return T* - */ - inline T *operator->() { return _data.get(); } - }; -} // namespace Dynamo \ No newline at end of file diff --git a/src/Asset/AssetCache.hpp b/src/Asset/AssetCache.hpp deleted file mode 100644 index 28ce3130..00000000 --- a/src/Asset/AssetCache.hpp +++ /dev/null @@ -1,108 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "../Log/Log.hpp" -#include "../Types.hpp" -#include "./Asset.hpp" -#include "./Loader/GeometryLoader.hpp" -#include "./Loader/SoundLoader.hpp" -#include "./Loader/TextureLoader.hpp" - -namespace Dynamo { - /** - * @brief Load and cache engine resources loaded from disk. - * - * This will automatically release resource memory as soon as all fetched - * handles are out of scope. - * - */ - class AssetCache { - std::unordered_map> _pool; - std::string _root; - - /** - * @brief Store a new asset in the cache with a key. - * - * @tparam T - * @param key - * @param ptr - */ - template - Asset store(const std::string key, T &&object) { - // Remove item from cache as soon as all handles are destroyed - auto deleter = [this, key](T *data) { - _pool.erase(key); - delete data; - }; - std::shared_ptr ptr(new T(object), deleter); - _pool[key] = ptr; - return Asset(ptr); - } - - /** - * @brief Load an asset from disk with the appropriate loader. - * - * @tparam T - * @param filename - */ - template - Asset load(const std::string filename) { - const std::string fullpath = _root + filename; - if constexpr (std::is_same_v) { - return store(filename, GeometryLoader::load(fullpath)); - } else if constexpr (std::is_same_v) { - return store(filename, SoundLoader::load(fullpath)); - } else if constexpr (std::is_same_v) { - return store(filename, TextureLoader::load(fullpath)); - } else { - Log::error("Attempted to load unsupported asset type."); - } - } - - public: - /** - * @brief Construct a new AssetCache object. - * - * @param asset_directory Root asset directory. - */ - AssetCache(const std::string asset_directory) : - _root(asset_directory) {} - - /** - * @brief Count the number of loaded assets. - * - * @return u32 - */ - inline u32 size() { return _pool.size(); } - - /** - * @brief Check if an asset file is in cache. - * - * @param filename Path to the file relative to the root directory. - * @return true - * @return false - */ - inline b8 contains(const std::string filename) { - return _pool.count(filename) > 0; - } - - /** - * @brief Fetch an asset from the cache. - * - * @param filename Path to the file relative to the root directory. - * @return Asset - */ - template - inline Asset get(const std::string filename) { - if (!contains(filename)) { - return load(filename); - } - auto ptr = std::static_pointer_cast(_pool.at(filename).lock()); - return Asset(ptr); - } - }; -} // namespace Dynamo \ No newline at end of file diff --git a/src/Asset/Loader/GeometryLoader.cpp b/src/Asset/Loader/GeometryLoader.cpp deleted file mode 100644 index 0418f7b8..00000000 --- a/src/Asset/Loader/GeometryLoader.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "./GeometryLoader.hpp" - -namespace Dynamo { - Graphics::Geometry GeometryLoader::load(const std::string filepath) { - tinyobj::attrib_t attrib; - - std::vector shapes; - std::vector materials; - std::string warning, error; - - b8 result = tinyobj::LoadObj(&attrib, - &shapes, - &materials, - &warning, - &error, - filepath.c_str()); - if (!result) { - Log::error("Could not load Obj file: {}, ", error, warning); - } - - // Generate the geometry - Graphics::Geometry geometry; - std::unordered_map unique_vertices; - for (const tinyobj::shape_t &shape : shapes) { - for (const tinyobj::index_t &index : shape.mesh.indices) { - Graphics::Vertex vertex; - vertex.position = { - attrib.vertices[3 * index.vertex_index + 0], - attrib.vertices[3 * index.vertex_index + 1], - attrib.vertices[3 * index.vertex_index + 2], - }; - - if (index.normal_index >= 0) { - vertex.normal = { - attrib.vertices[3 * index.normal_index + 0], - attrib.vertices[3 * index.normal_index + 1], - attrib.vertices[3 * index.normal_index + 2], - }; - } - - if (index.vertex_index >= 0) { - vertex.texture = { - attrib.texcoords[2 * index.texcoord_index + 0], - 1.0f - attrib.texcoords[2 * index.texcoord_index + 1], - }; - } - - if (unique_vertices.count(vertex) == 0) { - unique_vertices[vertex] = geometry.vertices.size(); - geometry.vertices.push_back(vertex); - } - geometry.indices.push_back(unique_vertices[vertex]); - } - } - return geometry; - } -} // namespace Dynamo \ No newline at end of file diff --git a/src/Asset/Loader/GeometryLoader.hpp b/src/Asset/Loader/GeometryLoader.hpp deleted file mode 100644 index 16e7e234..00000000 --- a/src/Asset/Loader/GeometryLoader.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include -#include -#include - -#include - -#include "../../Graphics/Geometry.hpp" -#include "../../Log/Log.hpp" -#include "../../Types.hpp" - -namespace Dynamo { - /** - * @brief Geometry loader. - * - */ - class GeometryLoader { - public: - /** - * @brief Load geometry from a file. - * - * @param filepath - * @return Graphics::Geometry - */ - static Graphics::Geometry load(const std::string filepath); - }; -} // namespace Dynamo \ No newline at end of file diff --git a/src/Asset/Loader/SoundLoader.cpp b/src/Asset/Loader/SoundLoader.cpp deleted file mode 100644 index d2c536bc..00000000 --- a/src/Asset/Loader/SoundLoader.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "SoundLoader.hpp" - -namespace Dynamo { - Sound::Sound SoundLoader::load(const std::string filepath) { - SndfileHandle file(filepath.c_str()); - if (file.error()) { - Log::error("Could not load sound file `{}`", filepath); - } - - u32 frames = file.frames(); - u32 channels = file.channels(); - u32 sample_rate = file.samplerate(); - - // Read the PCM data - Sound::WaveForm interleaved(frames * channels); - file.readf(interleaved.data(), interleaved.size()); - - // De-interleave the data into the final waveform buffer - Sound::WaveForm waveform(frames * channels); - for (u32 f = 0; f < frames; f++) { - for (u32 c = 0; c < channels; c++) { - waveform[c * frames + f] = interleaved[f * channels + c]; - } - } - - return Sound::Sound(waveform, channels, sample_rate); - } -} // namespace Dynamo \ No newline at end of file diff --git a/src/Asset/Loader/SoundLoader.hpp b/src/Asset/Loader/SoundLoader.hpp deleted file mode 100644 index cb6b4282..00000000 --- a/src/Asset/Loader/SoundLoader.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include -#include - -#include - -#include "../../Log/Log.hpp" -#include "../../Sound/Resample.hpp" -#include "../../Sound/Sound.hpp" -#include "../../Types.hpp" - -namespace Dynamo { - /** - * @brief Sound loader. - * - */ - class SoundLoader { - public: - /** - * @brief Load a sound from a file. - * - * @param filepath - * @return Sound::Sound - */ - static Sound::Sound load(const std::string filepath); - }; -} // namespace Dynamo \ No newline at end of file diff --git a/src/Asset/Loader/TextureLoader.cpp b/src/Asset/Loader/TextureLoader.cpp deleted file mode 100644 index f9147d7a..00000000 --- a/src/Asset/Loader/TextureLoader.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "./TextureLoader.hpp" - -namespace Dynamo { - Graphics::Texture TextureLoader::load(const std::string &filepath) { - i32 width, height, channels; - stbi_uc *raw = stbi_load(filepath.c_str(), - &width, - &height, - &channels, - STBI_rgb_alpha); - if (raw == nullptr) { - Log::error("Could not load image file: {}", filepath); - } - - Graphics::Texture texture; - texture.size.x = width; - texture.size.y = height; - - texture.pixels.resize(width * height * STBI_rgb_alpha); - std::copy(raw, raw + texture.pixels.size(), texture.pixels.data()); - stbi_image_free(raw); - - return texture; - } -} // namespace Dynamo \ No newline at end of file diff --git a/src/Asset/Loader/TextureLoader.hpp b/src/Asset/Loader/TextureLoader.hpp deleted file mode 100644 index 519864f9..00000000 --- a/src/Asset/Loader/TextureLoader.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include - -#include - -#include "../../Graphics/Texture.hpp" -#include "../../Log/Log.hpp" - -namespace Dynamo { - /** - * @brief Texture loader. - * - */ - class TextureLoader { - public: - /** - * @brief Load a texture from a file. - * - * @param filepath - * @return Graphics::Texture - */ - static Graphics::Texture load(const std::string &filepath); - }; -} // namespace Dynamo \ No newline at end of file diff --git a/src/Clock.cpp b/src/Clock.cpp new file mode 100644 index 00000000..f9145812 --- /dev/null +++ b/src/Clock.cpp @@ -0,0 +1,30 @@ +#include "Clock.hpp" + +namespace Dynamo { + Clock::Clock() { + _start = std::chrono::steady_clock::now().time_since_epoch(); + _delta = Seconds(0); + _prev = _start; + + _frames = 0; + } + + TimePoint Clock::time() { return std::chrono::system_clock::now(); } + + Seconds Clock::elapsed() const { + Seconds now = std::chrono::steady_clock::now().time_since_epoch(); + return now - _start; + } + + Seconds Clock::delta() const { return _delta; } + + unsigned long long Clock::frames() const { return _frames; } + + void Clock::tick() { + Seconds now = std::chrono::steady_clock::now().time_since_epoch(); + _delta = now - _prev; + _prev = now; + + _frames++; + } +} // namespace Dynamo \ No newline at end of file diff --git a/src/Clock.hpp b/src/Clock.hpp new file mode 100644 index 00000000..5d11560f --- /dev/null +++ b/src/Clock.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include + +namespace Dynamo { + /** + * @brief Standard unit of time. + * + */ + using Seconds = std::chrono::duration; + + /** + * @brief Time point. + * + */ + using TimePoint = std::chrono::system_clock::time_point; + + /** + * @brief Application time-keeper. + * + */ + class Clock { + Seconds _start; + Seconds _delta; + Seconds _prev; + + unsigned long long _frames; + + public: + /** + * @brief Initialize the clock. + * + */ + Clock(); + + /** + * @brief Get the current system time. + * + * @return TimePoint + */ + static TimePoint time(); + + /** + * @brief Get the total elapsed time since initialization. + * + * @return Seconds + */ + Seconds elapsed() const; + + /** + * @brief Get the delta time since the previous frame. + * + * @return Seconds + */ + Seconds delta() const; + + /** + * @brief Get the total number of frames since initialization. + * + * @return unsigned long long + */ + unsigned long long frames() const; + + /** + * @brief Tick the clock. + * + * @return Seconds + */ + void tick(); + }; + + /** + * @brief Clock reference. + * + */ + using ClockRef = std::reference_wrapper; +} // namespace Dynamo \ No newline at end of file diff --git a/src/Clock/Clock.cpp b/src/Clock/Clock.cpp deleted file mode 100644 index a593a4c4..00000000 --- a/src/Clock/Clock.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "Clock.hpp" - -namespace Dynamo { - Clock::Clock() { - _epoch = std::chrono::steady_clock::now().time_since_epoch(); - _delta = Seconds{0}; - _prev = time(); - - _frames = 0; - } - - Seconds Clock::time() { - Seconds now = std::chrono::steady_clock::now().time_since_epoch(); - return now - _epoch; - } - - Seconds Clock::delta() { return _delta; } - - Seconds Clock::epoch() { return _epoch; } - - i64 Clock::frames() { return _frames; } - - void Clock::tick() { - // Calculate delta time - Seconds now = time(); - _delta = now - _prev; - _prev = now; - - _frames++; - } -} // namespace Dynamo \ No newline at end of file diff --git a/src/Clock/Clock.hpp b/src/Clock/Clock.hpp deleted file mode 100644 index d9421eb3..00000000 --- a/src/Clock/Clock.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include - -#include "../Types.hpp" - -namespace Dynamo { - /** - * @brief Time duration in seconds. - * - */ - using Seconds = std::chrono::duration; - - /** - * @brief Internal clock for querying per-frame time information. - * - */ - class Clock { - Seconds _epoch; - Seconds _delta; - Seconds _prev; - - i64 _frames; - - public: - /** - * @brief Construct a new Clock object. - * - */ - Clock(); - - /** - * @brief Get the total time in seconds since initialization. - * - * @return Seconds - */ - Seconds time(); - - /** - * @brief Get the delta time in seconds since the previous frame. - * - * @return Seconds - */ - Seconds delta(); - - /** - * @brief Get the precise time in seconds of initialization. - * - * @return Seconds - */ - Seconds epoch(); - - /** - * @brief Get the number of frames since initialization. - * - * @return i64 - */ - i64 frames(); - - /** - * @brief Update the clock. - * - */ - void tick(); - }; -} // namespace Dynamo \ No newline at end of file diff --git a/src/Core/Core.hpp b/src/Core/Core.hpp deleted file mode 100644 index 5710cdae..00000000 --- a/src/Core/Core.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "../Clock/Clock.hpp" -#include "Display.hpp" -#include "Input.hpp" - -namespace Dynamo { - /** - * @brief Core modules used in every scene - * - */ - struct Core { - /** - * @brief Display instance - * - */ - Display &display; - - /** - * @brief Input handler - * - */ - Input &input; - - /** - * @brief Time manager - * - */ - Clock &clock; - }; -} // namespace Dynamo \ No newline at end of file diff --git a/src/Core/Display.cpp b/src/Core/Display.cpp deleted file mode 100644 index a8a9a2e9..00000000 --- a/src/Core/Display.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#define STB_IMAGE_IMPLEMENTATION -#include "Display.hpp" - -namespace Dynamo { - Display::Display(i32 width, - i32 height, - std::string title, - b8 fullscreen, - b8 vsync) { - _monitor = glfwGetPrimaryMonitor(); - if (!_monitor) { - Log::error("GLFW could not find primary monitor device."); - } - const GLFWvidmode *mode = glfwGetVideoMode(_monitor); - if (width == 0) width = mode->width; - if (height == 0) height = mode->height; - - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - _window = - glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr); - _size = Vec2(width, height); - _vsync = vsync; - _title = title; - - if (!_window) { - Log::error("Failed to create a GLFW window"); - } - glfwMakeContextCurrent(_window); - - set_fullscreen(fullscreen); - set_vsync(vsync); - } - - Display::~Display() { glfwDestroyWindow(_window); } - - GLFWwindow *Display::get_window() { return _window; } - - std::vector Display::get_vulkan_extensions() const { - std::vector extensions; - u32 count; - const i8 **arr = glfwGetRequiredInstanceExtensions(&count); - for (u32 i = 0; i < count; i++) { - extensions.push_back(arr[i]); - } - return extensions; - } - - vk::SurfaceKHR Display::get_vulkan_surface(vk::Instance instance) const { - VkSurfaceKHR surface; - vk::Result result = static_cast( - glfwCreateWindowSurface(instance, _window, nullptr, &surface)); - if (result != vk::Result::eSuccess) { - Log::error("Failed to create a Vulkan surface: {}", - vk::to_string(result)); - } - return surface; - } - - Vec2 Display::get_window_size() const { - i32 width, height; - glfwGetWindowSize(_window, &width, &height); - return Vec2(width, height); - } - - Vec2 Display::get_framebuffer_size() const { - i32 width, height; - glfwGetFramebufferSize(_window, &width, &height); - return Vec2(width, height); - } - - Vec2 Display::get_size() const { return _size; } - - std::string Display::get_title() const { return _title; } - - b8 Display::is_closed() const { return glfwWindowShouldClose(_window); } - - b8 Display::is_fullscreen() const { - return glfwGetWindowMonitor(_window) != nullptr; - } - - b8 Display::is_vsync() const { return _vsync; } - - void Display::set_size(Vec2 size) { - _size.x = size.x; - _size.y = size.y; - } - - void Display::set_title(std::string title) { - _title = title; - glfwSetWindowTitle(_window, _title.c_str()); - } - - void Display::set_fullscreen(b8 fullscreen) { - const GLFWvidmode *mode = glfwGetVideoMode(_monitor); - if (fullscreen) { - glfwSetWindowMonitor(_window, - _monitor, - mode->width / 2, - mode->height / 2, - mode->width, - mode->height, - mode->refreshRate); - } else { - glfwSetWindowMonitor(_window, - nullptr, - (mode->width - _size.x) / 2, - (mode->height - _size.y) / 2, - _size.x, - _size.y, - 0); - } - } - - void Display::set_vsync(b8 vsync) { - _vsync = vsync; - if (vsync) { - glfwSwapInterval(1); - } else { - glfwSwapInterval(0); - } - } - - void Display::set_icon(std::string filename) { - i32 width, height, channels; - stbi_uc *pixels = stbi_load(filename.c_str(), - &width, - &height, - &channels, - STBI_rgb_alpha); - if (!pixels) { - Log::warn("Could not load window icon file `{}`", filename); - return; - } - GLFWimage image = { - width, - height, - pixels, - }; - glfwSetWindowIcon(_window, 1, &image); - } -} // namespace Dynamo diff --git a/src/Core/Display.hpp b/src/Core/Display.hpp deleted file mode 100644 index 3fee5c51..00000000 --- a/src/Core/Display.hpp +++ /dev/null @@ -1,158 +0,0 @@ -#pragma once -#define GLFW_INCLUDE_VULKAN - -#include -#include -#include - -#include "../Log/Log.hpp" -#include "../Math/Vec2.hpp" -#include "../Types.hpp" - -namespace Dynamo { - /** - * @brief Display module exposes an interface for manipulating the - * application window. - * - */ - class Display { - GLFWmonitor *_monitor; - GLFWwindow *_window; - - Vec2 _size; - b8 _vsync; - - std::string _title; - - public: - /** - * @brief Construct a new Display object. - * - * @param width Initial width of the window. - * @param height Initial height of the window. - * @param title Title of the window. - * @param fullscreen Toggle fullscreen mode. - * @param vsync Toggle vsync. - */ - Display(i32 width, - i32 height, - std::string title, - b8 fullscreen, - b8 vsync); - - /** - * @brief Destroy the Display object. - * - */ - ~Display(); - - /** - * @brief Get the underlying GLFW window. - * - * @return GLFWwindow& - */ - GLFWwindow *get_window(); - - /** - * @brief Get the available Vulkan extensions. - * - * @return std::vector - */ - std::vector get_vulkan_extensions() const; - - /** - * @brief Get the Vulkan surface. - * - * @param instance - * @return vk::SurfaceKHR - */ - vk::SurfaceKHR get_vulkan_surface(vk::Instance instance) const; - - /** - * @brief Get the size of the display in screen coordinates. - * - * @return Vec2 - */ - Vec2 get_window_size() const; - - /** - * @brief Get the size of the framebuffer in pixels. - * - * @return Vec2 - */ - Vec2 get_framebuffer_size() const; - - /** - * @brief Get the logical size of the display. - * - * @return Vec2 - */ - Vec2 get_size() const; - - /** - * @brief Get the title of the window. - * - * @return std::string - */ - std::string get_title() const; - - /** - * @brief Is the display closed? - * - * @return true - * @return false - */ - b8 is_closed() const; - - /** - * @brief Is the display windowed or in fullscreen? - * - * @return true - * @return false - */ - b8 is_fullscreen() const; - - /** - * @brief Is vsync enabled? - * - * @return true - * @return false - */ - b8 is_vsync() const; - - /** - * @brief Set the logical size of the display. - * - * @param size - */ - void set_size(Vec2 size); - - /** - * @brief Set the title of the display. - * - * @param title - */ - void set_title(std::string title); - - /** - * @brief Toggle fullscreen or windowed. - * - * @param fullscreen - */ - void set_fullscreen(b8 fullscreen); - - /** - * @brief Toggle vsync. - * - * @param vsync - */ - void set_vsync(b8 vsync); - - /** - * @brief Set the icon of the window. - * - * @param filename Path to the image file. - */ - void set_icon(std::string filename); - }; -} // namespace Dynamo \ No newline at end of file diff --git a/src/Core/Input.cpp b/src/Core/Input.cpp deleted file mode 100644 index cde381e7..00000000 --- a/src/Core/Input.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "Input.hpp" - -namespace Dynamo { - Input::Input(Display &display) : _display(display) { - // Register input handling callbacks to update internal state - glfwSetWindowUserPointer(_display.get().get_window(), &_state); - - // On cursor motion - glfwSetCursorPosCallback(_display.get().get_window(), - [](GLFWwindow *window, f64 x, f64 y) { - InputState *state = - static_cast( - glfwGetWindowUserPointer(window)); - state->mouse_position.x = x; - state->mouse_position.y = y; - }); - - // On scroll - glfwSetScrollCallback(_display.get().get_window(), - [](GLFWwindow *window, f64 x, f64 y) { - InputState *state = static_cast( - glfwGetWindowUserPointer(window)); - state->scroll_offset.x = x; - state->scroll_offset.y = y; - }); - - // On key state change - glfwSetKeyCallback( - _display.get().get_window(), - [](GLFWwindow *window, - i32 key, - i32 scancode, - i32 action, - i32 mods) { - InputState *state = - static_cast(glfwGetWindowUserPointer(window)); - switch (action) { - case GLFW_PRESS: - state->key_pressed.insert(static_cast(key)); - break; - case GLFW_RELEASE: - state->key_released.insert(static_cast(key)); - break; - default: - break; - } - }); - - // On mouse button state change - glfwSetMouseButtonCallback( - _display.get().get_window(), - [](GLFWwindow *window, i32 button, i32 action, i32 mods) { - InputState *state = - static_cast(glfwGetWindowUserPointer(window)); - switch (action) { - case GLFW_PRESS: - state->mouse_pressed.insert(static_cast(button)); - break; - case GLFW_RELEASE: - state->mouse_released.insert( - static_cast(button)); - break; - default: - break; - } - }); - } - - const Vec2 &Input::get_mouse_position() const { - return _state.mouse_position; - } - - const Vec2 &Input::get_scroll_offset() const { - return _state.scroll_offset; - } - - b8 Input::is_pressed(KeyCode code) { - return _state.key_pressed.count(code); - } - - b8 Input::is_pressed(MouseCode code) { - return _state.mouse_pressed.count(code); - } - - b8 Input::is_released(KeyCode code) { - return _state.key_released.count(code); - } - - b8 Input::is_released(MouseCode code) { - return _state.mouse_released.count(code); - } - - b8 Input::is_down(KeyCode code) { - return glfwGetKey(_display.get().get_window(), - static_cast(code)) == GLFW_PRESS; - } - - b8 Input::is_down(MouseCode code) { - return glfwGetMouseButton(_display.get().get_window(), - static_cast(code)) == GLFW_PRESS; - } - - void Input::poll() { - // Reset scroll state - _state.scroll_offset.x = 0; - _state.scroll_offset.y = 0; - - // Reset key states - _state.key_pressed.clear(); - _state.key_released.clear(); - - // Reset mouse button states - _state.mouse_pressed.clear(); - _state.mouse_released.clear(); - - glfwPollEvents(); - } -} // namespace Dynamo \ No newline at end of file diff --git a/src/Display.cpp b/src/Display.cpp new file mode 100644 index 00000000..bc1eed39 --- /dev/null +++ b/src/Display.cpp @@ -0,0 +1,119 @@ +#define STB_IMAGE_IMPLEMENTATION +#include "Display.hpp" +#include "Utils/Log.hpp" + +namespace Dynamo { + Display::Display(const std::string &title, + unsigned window_width, + unsigned window_height) { + if (!glfwInit()) { + Log::error("GLFW failed to initialize."); + } + + _monitor = glfwGetPrimaryMonitor(); + if (!_monitor) { + Log::error("GLFW could not find the primary monitor."); + } + + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); + _window = glfwCreateWindow(window_width, + window_height, + title.c_str(), + nullptr, + nullptr); + if (!_window) { + Log::error("GLFW failed to create a display window."); + } + + glfwMakeContextCurrent(_window); + + _vsync = true; + _input = std::make_unique(_window); + } + + Display::~Display() { + glfwDestroyWindow(_window); + glfwTerminate(); + } + + Input &Display::get_input() { return *_input; } + + Vec2 Display::get_window_size() const { + int width, height; + glfwGetWindowSize(_window, &width, &height); + return Vec2(width, height); + } + + Vec2 Display::get_framebuffer_size() const { + int width, height; + glfwGetFramebufferSize(_window, &width, &height); + return Vec2(width, height); + } + + bool Display::is_open() const { return !glfwWindowShouldClose(_window); } + + bool Display::is_fullscreen() const { + return glfwGetWindowMonitor(_window) != nullptr; + } + + bool Display::is_vsync() const { return _vsync; } + + void Display::set_window_size(Vec2 size) { + glfwSetWindowSize(_window, size.x, size.y); + } + + void Display::set_fullscreen(bool flag) { + Vec2 size = get_window_size(); + const GLFWvidmode *mode = glfwGetVideoMode(_monitor); + if (flag) { + glfwSetWindowMonitor(_window, + _monitor, + mode->width / 2, + mode->height / 2, + mode->width, + mode->height, + mode->refreshRate); + } else { + glfwSetWindowMonitor(_window, + nullptr, + (mode->width - size.x) / 2, + (mode->height - size.y) / 2, + size.x, + size.y, + 0); + } + } + + void Display::set_vsync(bool flag) { + _vsync = flag; + if (_vsync) { + glfwSwapInterval(1); + } else { + glfwSwapInterval(0); + } + } + + void Display::set_title(const std::string &title) { + glfwSetWindowTitle(_window, title.c_str()); + } + + void Display::set_icon(const std::string &filepath) { + int width, height, channels; + stbi_uc *pixels = stbi_load(filepath.c_str(), + &width, + &height, + &channels, + STBI_rgb_alpha); + if (!pixels) { + Log::warn("Could not load window icon file `{}`", filepath); + return; + } + GLFWimage image = { + width, + height, + pixels, + }; + glfwSetWindowIcon(_window, 1, &image); + } +} // namespace Dynamo \ No newline at end of file diff --git a/src/Display.hpp b/src/Display.hpp new file mode 100644 index 00000000..a3ff12d4 --- /dev/null +++ b/src/Display.hpp @@ -0,0 +1,125 @@ +#pragma once +#define GLFW_INCLUDE_VULKAN + +#include +#include + +#include +#include + +#include "./Input.hpp" +#include "./Math/Vec2.hpp" + +namespace Dynamo { + /** + * @brief Display window. + * + */ + class Display { + GLFWmonitor *_monitor; + GLFWwindow *_window; + + bool _vsync; + + std::unique_ptr _input; + + public: + /** + * @brief Initialize the display. + * + * @param title + * @param window_width + * @param window_height + */ + Display(const std::string &title, + unsigned window_width, + unsigned window_height); + ~Display(); + + /** + * @brief Get the Input subsystem. + * + * @return Input& + */ + Input &get_input(); + + /** + * @brief Get the window size. + * + * @return Vec2 + */ + Vec2 get_window_size() const; + + /** + * @brief Get the framebuffer size. + * + * @return Vec2 + */ + Vec2 get_framebuffer_size() const; + + /** + * @brief Check if the display is open. + * + * @return true + * @return false + */ + bool is_open() const; + + /** + * @brief Check if fullscreen mode is enabled. + * + * @return true + * @return false + */ + bool is_fullscreen() const; + + /** + * @brief Check if vsync is enabled. + * + * @return true + * @return false + */ + bool is_vsync() const; + + /** + * @brief Set the window size. + * + * @param size + */ + void set_window_size(Vec2 size); + + /** + * @brief Set fullscreen mode. + * + * @param flag + */ + void set_fullscreen(bool flag); + + /** + * @brief Set vsync. + * + * @param flag + */ + void set_vsync(bool flag); + + /** + * @brief Set the title of the window. + * + * @param title + */ + void set_title(const std::string &title); + + /** + * @brief Set the icon of the window. + * + * @param filepath + */ + void set_icon(const std::string &filepath); + }; + + /** + * @brief Display reference. + * + */ + using DisplayRef = std::reference_wrapper; +} // namespace Dynamo \ No newline at end of file diff --git a/src/Dynamo.hpp b/src/Dynamo.hpp index 30a7b4a7..7f4bb45e 100644 --- a/src/Dynamo.hpp +++ b/src/Dynamo.hpp @@ -1,58 +1,27 @@ -#pragma once - -#include "Application/Application.hpp" - -#include "Clock/Clock.hpp" -#include "Core/Core.hpp" -#include "Core/Display.hpp" -#include "Core/Input.hpp" - -#include "Graphics/Geometry.hpp" -#include "Graphics/Renderer.hpp" -#include "Graphics/Vulkan/Renderer.hpp" - -#include "Sound/Chunk.hpp" -#include "Sound/Convolver.hpp" -#include "Sound/Device.hpp" -#include "Sound/Filters/Attenuation.hpp" -#include "Sound/Filters/Binaural.hpp" -#include "Sound/Filters/Filter.hpp" -#include "Sound/Filters/Stereo.hpp" -#include "Sound/HRTF.hpp" -#include "Sound/Jukebox.hpp" -#include "Sound/Listener.hpp" -#include "Sound/Material.hpp" -#include "Sound/Resample.hpp" -#include "Sound/Sound.hpp" - -#include "Asset/Asset.hpp" -#include "Asset/AssetCache.hpp" -#include "Asset/Loader/GeometryLoader.hpp" -#include "Asset/Loader/SoundLoader.hpp" - -#include "Math/Box2.hpp" -#include "Math/Circle.hpp" -#include "Math/Color.hpp" -#include "Math/Common.hpp" -#include "Math/Complex.hpp" -#include "Math/Delaunay.hpp" -#include "Math/Fourier.hpp" -#include "Math/Matrix.hpp" -#include "Math/Quaternion.hpp" -#include "Math/Segment2.hpp" -#include "Math/Triangle2.hpp" -#include "Math/Vec2.hpp" -#include "Math/Vec3.hpp" - -#include "Utils/Allocator.hpp" -#include "Utils/Bits.hpp" -#include "Utils/ChannelData.hpp" -#include "Utils/IdTracker.hpp" -#include "Utils/Random.hpp" -#include "Utils/RingBuffer.hpp" -#include "Utils/SparseSet.hpp" -#include "Utils/ThreadPool.hpp" -#include "Utils/TypeId.hpp" - -#include "Log/Log.hpp" -#include "Log/Message.hpp" \ No newline at end of file +#include "./Application.hpp" +#include "./Clock.hpp" +#include "./Display.hpp" +#include "./Input.hpp" +#include "./Math/Box2.hpp" +#include "./Math/Circle.hpp" +#include "./Math/Color.hpp" +#include "./Math/Common.hpp" +#include "./Math/Complex.hpp" +#include "./Math/Delaunay.hpp" +#include "./Math/Fourier.hpp" +#include "./Math/Matrix.hpp" +#include "./Math/Quaternion.hpp" +#include "./Math/Segment2.hpp" +#include "./Math/Triangle2.hpp" +#include "./Math/Vec2.hpp" +#include "./Math/Vec3.hpp" +#include "./Utils/Allocator.hpp" +#include "./Utils/Bits.hpp" +#include "./Utils/ChannelData.hpp" +#include "./Utils/IdTracker.hpp" +#include "./Utils/Log.hpp" +#include "./Utils/Random.hpp" +#include "./Utils/RingBuffer.hpp" +#include "./Utils/SparseSet.hpp" +#include "./Utils/ThreadPool.hpp" +#include "./Utils/TypeId.hpp" \ No newline at end of file diff --git a/src/Graphics/Geometry.hpp b/src/Graphics/Geometry.hpp deleted file mode 100644 index fe9f99e9..00000000 --- a/src/Graphics/Geometry.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include - -#include "../Types.hpp" -#include "./Vertex.hpp" - -namespace Dynamo::Graphics { - /** - * @brief 3D Geometry structure - * - */ - struct Geometry { - /** - * @brief Ordered array of vertices - * - */ - std::vector vertices; - - /** - * @brief Ordered array of indices to the vertex array - * - */ - std::vector indices; - }; -} // namespace Dynamo::Graphics \ No newline at end of file diff --git a/src/Graphics/GeometryInstance.hpp b/src/Graphics/GeometryInstance.hpp deleted file mode 100644 index 592c8bff..00000000 --- a/src/Graphics/GeometryInstance.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include "../Types.hpp" -#include "./Geometry.hpp" - -namespace Dynamo::Graphics { - /** - * @brief Defines an array range. - * - */ - struct BufferRange { - u32 offset; - u32 count; - }; - - /** - * @brief Instance of a geometry in the GPU buffer. - * - */ - class GeometryInstance { - public: - /** - * @brief Destroy the GeometryInstance object. - * - */ - virtual ~GeometryInstance() = 0; - - /** - * @brief Get the range of the vertex buffer. - * - * @return u32 - */ - virtual const BufferRange &get_vertex_range() const = 0; - - /** - * @brief Get the range of the index buffer. - * - * @return u32 - */ - virtual const BufferRange &get_index_range() const = 0; - }; -} // namespace Dynamo::Graphics \ No newline at end of file diff --git a/src/Graphics/Material.hpp b/src/Graphics/Material.hpp deleted file mode 100644 index bb9cab65..00000000 --- a/src/Graphics/Material.hpp +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once - -#include - -#include "../Math/Color.hpp" -#include "../Types.hpp" -#include "Graphics/Shader.hpp" -#include "Utils/IdTracker.hpp" - -namespace Dynamo::Graphics { - /** - * @brief Enumerates the culling modes. - * - */ - enum class CullMode { - /** - * @brief Culling is disabled. - * - */ - None, - - /** - * @brief Front face is culled. - * - */ - Front, - - /** - * @brief Backface is culled. - * - */ - Back - }; - - /** - * @brief Enumerates the polygon geometry render modes. - * - */ - enum class PolygonMode { - /** - * @brief Color fill. - * - */ - Fill, - - /** - * @brief Wireframe mesh. - * - */ - Line, - - /** - * @brief Point cloud. - * - */ - Point, - }; - - /** - * @brief Describes the basic visual properties of a drawn model. - * - */ - struct Material { - /** - * @brief Enable writing to the color buffer. - * - */ - b8 color_write; - - /** - * @brief Enable writing to the depth buffer. - * - */ - b8 depth_write; - - /** - * @brief Enable writing to the stencil buffer. - * - */ - b8 stencil_write; - - /** - * @brief Enable rendering geometry with colors embedded in the vertex - * attributes. - * - */ - b8 vertex_colors; - - /** - * @brief Transparency value [0 - 1]. - * - */ - f32 opacity; - - /** - * @brief Cull mode. - * - */ - CullMode cull_mode; - - /** - * @brief Polygon mode. - * - */ - PolygonMode polygon_mode; - - /** - * @brief Shader list. - * - */ - ShaderList shaders; - - /** - * @brief Build the material. - * - */ - virtual void build() = 0; - }; -} // namespace Dynamo::Graphics \ No newline at end of file diff --git a/src/Graphics/Renderer.hpp b/src/Graphics/Renderer.hpp deleted file mode 100644 index 652fbf0b..00000000 --- a/src/Graphics/Renderer.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include - -#include "../Core/Display.hpp" -#include "../Math/Color.hpp" -#include "./Geometry.hpp" -#include "./GeometryInstance.hpp" -#include "./Target.hpp" -#include "./Texture.hpp" - -namespace Dynamo::Graphics { - /** - * @brief Abstract graphics rendering engine for drawing 2D and 3D objects. - * - */ - class Renderer { - public: - /** - * @brief Destroy the Renderer object. - * - */ - virtual ~Renderer() = 0; - - /** - * @brief Upload geometry to the GPU and get a handle to its instance. - * - * @param geometry - * @return std::unique_ptr - */ - virtual std::unique_ptr - add_geometry(Geometry &geometry) = 0; - - /** - * @brief Upload a shader program to the GPU and get a handle to its - * instance. - * - * @param shader_code - * @param stage - * @return std::unique_ptr - */ - virtual std::unique_ptr - add_shader(const std::string shader_code, ShaderStage stage) = 0; - - /** - * @brief Upload a texture to the GPU and get a handle to the resulting - * render target. - * - * @param texture - * @return std::unique_ptr - */ - virtual std::unique_ptr add_target(Texture &texture) = 0; - - /** - * @brief Create a blank render target. - * - * @return std::unique_ptr - */ - virtual std::unique_ptr add_target() = 0; - - /** - * @brief Get the list of render targets. - * - * @return std::vector>& - */ - virtual std::vector> &get_targets() = 0; - - /** - * @brief Perform the rendering operations. - * - */ - virtual void refresh() = 0; - }; -} // namespace Dynamo::Graphics \ No newline at end of file diff --git a/src/Graphics/Shader.hpp b/src/Graphics/Shader.hpp deleted file mode 100644 index b14201ae..00000000 --- a/src/Graphics/Shader.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once - -#include -#include - -#include "../Types.hpp" - -namespace Dynamo::Graphics { - /** - * @brief Enumerates the shader stages. - * - */ - enum class ShaderStage { - /** - * @brief Vertex processing shader. - * - */ - Vertex, - - /** - * @brief Primitive processing shader. - * - */ - Geometry, - - /** - * @brief Pixel rasterization shader. - * - */ - Fragment, - - /** - * @brief General purpose computation shader. - * - */ - Compute, - }; - - /** - * @brief Shader program module. - * - */ - class Shader { - public: - /** - * @brief Destroy the Shader object. - * - */ - virtual ~Shader() = 0; - - /** - * @brief Get the pipeline stage of this shader. - * - * @return ShaderStage - */ - virtual ShaderStage get_stage() const = 0; - - /** - * @brief Get the compiled shader byecode. - * - * @return const std::vector& - */ - virtual const std::vector &get_bytecode() const = 0; - }; - - /** - * @brief List of shader modules. - * - */ - using ShaderList = std::vector>; -} // namespace Dynamo::Graphics \ No newline at end of file diff --git a/src/Graphics/Target.hpp b/src/Graphics/Target.hpp deleted file mode 100644 index ea49296b..00000000 --- a/src/Graphics/Target.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include "../Math/Box2.hpp" -#include "./View.hpp" - -namespace Dynamo::Graphics { - /** - * @brief Target for rendering. - * - */ - class Target { - public: - /** - * @brief Destroy the Target object. - * - */ - virtual ~Target() = 0; - - /** - * @brief Get the width of the render target. - * - * @return u32 - */ - virtual u32 get_width() const = 0; - - /** - * @brief Get the height of the render target. - * - * @return u32 - */ - virtual u32 get_height() const = 0; - - /** - * @brief Get the list of all views in this render target. - * - * @return const std::vector>& - */ - virtual const std::vector> &get_views() = 0; - - /** - * @brief Add a view to the render target. - * - * @return std::unique_ptr - */ - virtual std::unique_ptr add_view() = 0; - }; -} // namespace Dynamo::Graphics \ No newline at end of file diff --git a/src/Graphics/Texture.hpp b/src/Graphics/Texture.hpp deleted file mode 100644 index 7d680465..00000000 --- a/src/Graphics/Texture.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include - -#include "../Math/Vec2.hpp" -#include "../Types.hpp" - -namespace Dynamo::Graphics { - /** - * @brief Texture image. - * - */ - struct Texture { - /** - * @brief 4-channel pixel data. - * - */ - std::vector pixels; - - /** - * @brief Dimensions of the image. - * - */ - Vec2 size; - }; -} // namespace Dynamo::Graphics \ No newline at end of file diff --git a/src/Graphics/Vertex.hpp b/src/Graphics/Vertex.hpp deleted file mode 100644 index 07a40918..00000000 --- a/src/Graphics/Vertex.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include "../Math/Vec2.hpp" -#include "../Math/Vec3.hpp" -#include "../Types.hpp" - -namespace Dynamo::Graphics { - /** - * @brief Vertex object. - * - */ - struct Vertex { - Vec3 position; - Vec3 normal; - Vec2 texture; - - /** - * @brief Equality operator. - * - * @param rhs - * @return true - * @return false - */ - inline b8 operator==(const Vertex &rhs) const { - return position == rhs.position && normal == rhs.normal && - texture == rhs.texture; - } - }; -} // namespace Dynamo::Graphics - -/** - * @brief Hash function implementation for Vertex. - * - * @tparam - */ -template <> -struct std::hash { - inline size_t operator()(const Dynamo::Graphics::Vertex &vertex) const { - size_t tp = std::hash{}(vertex.position); - size_t tn = std::hash{}(vertex.normal); - size_t tt = std::hash{}(vertex.texture); - return (((tp ^ (tn << 1)) >> 1) ^ (tt << 2)) >> 2; - } -}; diff --git a/src/Graphics/View.hpp b/src/Graphics/View.hpp deleted file mode 100644 index b856f290..00000000 --- a/src/Graphics/View.hpp +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include "../Math/Box2.hpp" -#include "../Math/Color.hpp" -#include "../Math/Matrix.hpp" -#include "../Math/Vec2.hpp" -#include "../Types.hpp" -#include "./GeometryInstance.hpp" -#include "./Material.hpp" - -namespace Dynamo::Graphics { - /** - * @brief Defines the extent of the rendering area. - * - */ - struct Viewport : public Box2 { - f32 min_depth; - f32 max_depth; - }; - - /** - * @brief An area of the rendering target to draw to. - * - */ - class View { - public: - /** - * @brief Destroy the View object. - * - */ - virtual ~View() = 0; - - /** - * @brief Get a reference to the viewport. - * - * @return Viewport& - */ - virtual Viewport &get_viewport() = 0; - - /** - * @brief Get a reference to the scissor clipping boundary. - * - * @return Box2& - */ - virtual Box2 &get_scissor() = 0; - - /** - * @brief Draw a model. - * - * @param geometry Model geometry - * @param material Model material - * @param transforms Array of transforms for instanced rendering - */ - virtual void draw(GeometryInstance &geometry, - Material &material, - std::vector> &transforms) = 0; - - /** - * @brief Set the clear color of the view. - * - * @param color - */ - virtual void clear(Color color) = 0; - }; -} // namespace Dynamo::Graphics \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Buffer.cpp b/src/Graphics/Vulkan/Core/Buffer.cpp deleted file mode 100644 index 86185be4..00000000 --- a/src/Graphics/Vulkan/Core/Buffer.cpp +++ /dev/null @@ -1,171 +0,0 @@ -#include "./Buffer.hpp" - -namespace Dynamo::Graphics::Vulkan { - Buffer::Buffer(Device &device, - u32 size, - MemoryPool &memory_pool, - CommandPool &command_pool, - vk::Queue &transfer_queue, - vk::BufferUsageFlags usage, - vk::MemoryPropertyFlags properties) : - _handle(create_raw_buffer(device.get_handle(), size, usage)), - _device(device), _allocator(size), - _memory(memory_pool.allocate(get_memory_requirements(), properties)), - _memory_pool(memory_pool), _command_pool(command_pool) { - _usage = usage; - _properties = properties; - - _transfer_queue = transfer_queue; - _command_buffer = std::move( - command_pool.allocate(vk::CommandBufferLevel::ePrimary, 1)[0]); - - _memory.bind(_handle); - } - - Buffer::Buffer(Device &device, - MemoryPool &memory_pool, - CommandPool &command_pool, - vk::Queue &transfer_queue, - vk::BufferUsageFlags usage, - vk::MemoryPropertyFlags properties) : - Buffer(device, - DEFAULT_BUFFER_SIZE, - memory_pool, - command_pool, - transfer_queue, - usage, - properties) {} - - Buffer::~Buffer() { _device.get().get_handle().destroyBuffer(_handle); } - - vk::Buffer Buffer::create_raw_buffer(const vk::Device &device, - u32 size, - vk::BufferUsageFlags usage) { - vk::BufferCreateInfo buffer_info; - buffer_info.size = size; - buffer_info.usage = usage | vk::BufferUsageFlagBits::eTransferDst | - vk::BufferUsageFlagBits::eTransferSrc; - - return device.createBuffer(buffer_info); - } - - void Buffer::grow(u32 size) { - // Allocate new memory and buffer - vk::Buffer new_handle = - create_raw_buffer(_device.get().get_handle(), size, _usage); - MemoryBlock new_memory = _memory_pool.get().allocate( - _device.get().get_handle().getBufferMemoryRequirements(new_handle), - _properties); - new_memory.bind(new_handle); - - // Reset the command pool - _command_pool.get().reset( - vk::CommandPoolResetFlagBits::eReleaseResources); - - // Perform the copy - vk::CommandBufferBeginInfo begin_info; - begin_info.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit; - _command_buffer->begin(begin_info); - - vk::BufferCopy copy_region; - copy_region.dstOffset = 0; - copy_region.srcOffset = 0; - copy_region.size = _allocator.capacity(); - _command_buffer->copyBuffer(_handle, new_handle, copy_region); - - _command_buffer->end(); - - // Submit the command to the transfer queue - vk::SubmitInfo submit_info; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &_command_buffer.get(); - - _transfer_queue.submit(submit_info, nullptr); - _transfer_queue.waitIdle(); - - // Reassign - _device.get().get_handle().destroyBuffer(_handle); - _handle = new_handle; - _memory = std::move(new_memory); - - // Update the allocator - _allocator.grow(size); - } - - const vk::Buffer &Buffer::get_handle() const { return _handle; } - - vk::MemoryRequirements Buffer::get_memory_requirements() const { - return _device.get().get_handle().getBufferMemoryRequirements(_handle); - } - - u32 Buffer::reserve(u32 size, u32 alignment) { - std::optional result = _allocator.reserve(size, alignment); - if (result.has_value()) { - return result.value(); - } else { - u32 current = _allocator.capacity(); - grow(std::max(align_size(current + size, 2), current * 2)); - - // If this fails, we're in trouble... - return _allocator.reserve(size, alignment).value(); - } - } - - void Buffer::free(u32 offset) { return _allocator.free(offset); } - - void Buffer::write(i8 *src, u32 offset, u32 length) { - if (!_allocator.is_reserved(offset)) { - Log::error("Invalid Vulkan buffer offset write"); - } - _memory.write(src, offset, length); - } - - void Buffer::read(i8 *dst, u32 offset, u32 length) { - if (!_allocator.is_reserved(offset)) { - Log::error("Invalid Vulkan buffer offset read"); - } - _memory.read(dst, offset, length); - } - - u32 Buffer::capacity() const { return _allocator.capacity(); } - - u32 Buffer::size(u32 offset) const { - return _allocator.size(offset); - } - - void Buffer::copy(Buffer &dst, - u32 src_offset, - u32 dst_offset, - u32 length) { - // Make sure there is enough space - if (length > dst.size(dst_offset)) { - Log::error("Attempted to copy Vulkan buffer contents to " - "destination block with inadequate size."); - } - - // Reset the command pool - _command_pool.get().reset( - vk::CommandPoolResetFlagBits::eReleaseResources); - - // Perform the copy - vk::CommandBufferBeginInfo begin_info; - begin_info.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit; - _command_buffer->begin(begin_info); - - vk::BufferCopy copy_region; - copy_region.dstOffset = dst_offset; - copy_region.srcOffset = src_offset; - copy_region.size = length; - _command_buffer->copyBuffer(_handle, dst.get_handle(), copy_region); - - _command_buffer->end(); - - // Submit the command to the transfer queue - vk::SubmitInfo submit_info; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &_command_buffer.get(); - - _transfer_queue.submit(submit_info, nullptr); - _transfer_queue.waitIdle(); - } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Buffer.hpp b/src/Graphics/Vulkan/Core/Buffer.hpp deleted file mode 100644 index ff94c2f8..00000000 --- a/src/Graphics/Vulkan/Core/Buffer.hpp +++ /dev/null @@ -1,174 +0,0 @@ -#pragma once - -#include - -#include - -#include "../../../Types.hpp" -#include "../../../Utils/Allocator.hpp" -#include "./CommandPool.hpp" -#include "./Device.hpp" -#include "./MemoryPool.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Initial size of a Vulkan buffer. - * - */ - constexpr u32 DEFAULT_BUFFER_SIZE = (1 << 20); - - /** - * @brief Wrapper class of Vulkan Buffer. - * - */ - class Buffer { - vk::Buffer _handle; - std::reference_wrapper _device; - Allocator _allocator; - MemoryBlock _memory; - - std::reference_wrapper _memory_pool; - std::reference_wrapper _command_pool; - - vk::BufferUsageFlags _usage; - vk::MemoryPropertyFlags _properties; - - vk::Queue _transfer_queue; - vk::UniqueCommandBuffer _command_buffer; - - /** - * @brief Create a vk::Buffer handle. - * - * @param device vk::Device handle - * @param size Size of the buffer - * @param usage Buffer usage flags - * @return vk::Buffer - */ - static vk::Buffer create_raw_buffer(const vk::Device &device, - u32 size, - vk::BufferUsageFlags usage); - - /** - * @brief Grow the buffer. - * - * @param size - */ - void grow(u32 size); - - public: - /** - * @brief Construct a new Buffer object. - * - * @param device Reference to the logical device - * @param size Initial size of the buffer - * @param memory_pool Reference to the memory pool - * @param command_pool Reference to the command pool - * @param transfer_queue Transfer command queue - * @param usage Buffer usage flags - * @param properties Underlying buffer memory propertes - */ - Buffer(Device &device, - u32 size, - MemoryPool &memory_pool, - CommandPool &command_pool, - vk::Queue &transfer_queue, - vk::BufferUsageFlags usage, - vk::MemoryPropertyFlags properties); - - /** - * @brief Construct a new Buffer object. - * - * @param device Reference to the logical device - * @param memory_pool Reference to the memory pool - * @param command_pool Reference to the command pool - * @param transfer_queue Transfer command queue - * @param usage Buffer usage flags - * @param properties Underlying buffer memory propertes - */ - Buffer(Device &device, - MemoryPool &memory_pool, - CommandPool &command_pool, - vk::Queue &transfer_queue, - vk::BufferUsageFlags usage, - vk::MemoryPropertyFlags properties); - - /** - * @brief Destroy the Buffer object. - * - */ - ~Buffer(); - - /** - * @brief Get the handle to vk::Buffer - * - * @return const vk::Buffer& - */ - const vk::Buffer &get_handle() const; - - /** - * @brief Get the memory requirements for the buffer. - * - * @return vk::MemoryRequirements - */ - vk::MemoryRequirements get_memory_requirements() const; - - /** - * @brief Reserve a block of memory with specific alignment - * requirements, returning the offset within the buffer. - * - * @param size Desired size in bytes - * @param alignment Alignment requirement in bytes - * @return u32 - */ - u32 reserve(u32 size, u32 alignment); - - /** - * @brief Free the block of reserved memory at an offset. - * - * @param offset Offset within the buffer in bytes returned by reserve() - */ - void free(u32 offset); - - /** - * @brief Get the total capacity of the buffer. - * - * @return u32 - */ - u32 capacity() const; - - /** - * @brief Get the size of a reserved memory block. - * - * @param offset Offset within the buffer in bytes returned by reserve() - */ - u32 size(u32 offset) const; - - /** - * @brief Write to the underlying memory. - * - * @param src Source buffer - * @param offset Offset within the buffer in bytes returned by reserve() - * @param length Length of the write in bytes - */ - void write(i8 *src, u32 offset, u32 length); - - /** - * @brief Read from the underlying memory. - * - * @param dst Destination buffer - * @param offset Offset within the buffer in bytes returned by reserve() - * @param length Length of the read in bytes - */ - void read(i8 *dst, u32 offset, u32 length); - - /** - * @brief Copy the contents of a buffer block to another buffer. - * - * @param dst Destination buffer - * @param src_offset Valid source offset - * @param dst_offset Valid destination offset - * @param length Length of the copy <= destination block size - */ - void copy(Buffer &dst, u32 src_offset, u32 dst_offset, u32 length); - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/CommandPool.cpp b/src/Graphics/Vulkan/Core/CommandPool.cpp deleted file mode 100644 index 484cc039..00000000 --- a/src/Graphics/Vulkan/Core/CommandPool.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "./CommandPool.hpp" - -namespace Dynamo::Graphics::Vulkan { - CommandPool::CommandPool(Device &device, QueueFamily family) : - _device(device), _family(family) { - vk::CommandPoolCreateInfo pool_info; - pool_info.queueFamilyIndex = - _device.get().get_physical().get_queue_properties(family).family_id; - _handle = _device.get().get_handle().createCommandPool(pool_info); - } - - CommandPool::~CommandPool() { - _device.get().get_handle().destroyCommandPool(_handle); - } - - const vk::CommandPool &CommandPool::get_handle() const { return _handle; } - - QueueFamily CommandPool::get_family() const { return _family; } - - std::vector - CommandPool::allocate(vk::CommandBufferLevel level, u32 count) { - vk::CommandBufferAllocateInfo alloc_info; - alloc_info.commandPool = _handle; - alloc_info.level = level; - alloc_info.commandBufferCount = count; - - return _device.get().get_handle().allocateCommandBuffersUnique( - alloc_info); - } - - void CommandPool::reset(vk::CommandPoolResetFlags flags) { - _device.get().get_handle().resetCommandPool(_handle, flags); - } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/CommandPool.hpp b/src/Graphics/Vulkan/Core/CommandPool.hpp deleted file mode 100644 index 0f97c523..00000000 --- a/src/Graphics/Vulkan/Core/CommandPool.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include - -#include - -#include "../../../Types.hpp" -#include "./Device.hpp" -#include "./PhysicalDevice.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Wrapper class for a Vulkan command pool. This allocates command - * buffer sets of a given level. - * - */ - class CommandPool { - vk::CommandPool _handle; - std::reference_wrapper _device; - QueueFamily _family; - - public: - /** - * @brief Construct a new CommandPool object. - * - * @param device Reference to the logical device - * @param family Queue family - */ - CommandPool(Device &device, QueueFamily family); - - /** - * @brief Destroy the CommandPool object. - * - */ - ~CommandPool(); - - /** - * @brief Get the handle to vk::CommandPool. - * - * @return const vk::CommandPool& - */ - const vk::CommandPool &get_handle() const; - - /** - * @brief Get the queue family of this allocator. - * - * @return QueueFamily - */ - QueueFamily get_family() const; - - /** - * @brief Allocate a set of command buffers. - * - * @param level Command buffer level - * @param count Number of buffers to allocate - * @return std::vector - */ - std::vector - allocate(vk::CommandBufferLevel level, u32 count); - - /** - * @brief Reset the command pool. - * - * @param flags - */ - void reset(vk::CommandPoolResetFlags flags); - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Debugger.cpp b/src/Graphics/Vulkan/Core/Debugger.cpp deleted file mode 100644 index 668e6f6a..00000000 --- a/src/Graphics/Vulkan/Core/Debugger.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "./Debugger.hpp" - -static PFN_vkCreateDebugUtilsMessengerEXT vk_create_debugger_dispatch; -static PFN_vkDestroyDebugUtilsMessengerEXT vk_destroy_debugger_dispatch; - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT( - VkInstance instance, - const VkDebugUtilsMessengerCreateInfoEXT *create_info, - const VkAllocationCallbacks *allocator, - VkDebugUtilsMessengerEXT *messenger) { - return vk_create_debugger_dispatch(instance, - create_info, - allocator, - messenger); -} - -VKAPI_ATTR void VKAPI_CALL -vkDestroyDebugUtilsMessengerEXT(VkInstance instance, - VkDebugUtilsMessengerEXT messenger, - VkAllocationCallbacks const *allocator) { - vk_destroy_debugger_dispatch(instance, messenger, allocator); -} - -namespace Dynamo::Graphics::Vulkan { - Debugger::Debugger(vk::Instance &instance) { - load_proxies(instance); - - // Create the debug messenger - vk::DebugUtilsMessengerCreateInfoEXT create_info; - create_info.messageSeverity = - vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning | - vk::DebugUtilsMessageSeverityFlagBitsEXT::eError; - create_info.messageType = - vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral | - vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation | - vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance; - create_info.pfnUserCallback = &message_callback; - - _messenger = instance.createDebugUtilsMessengerEXTUnique(create_info); - } - - VKAPI_ATTR VkBool32 VKAPI_CALL - Debugger::message_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, - VkDebugUtilsMessageTypeFlagsEXT type, - VkDebugUtilsMessengerCallbackDataEXT const *data, - void *user_data) { - - Log::warn("--- Vulkan Debugger Message ---"); - Log::warn("Message name: {}", data->pMessageIdName); - Log::warn("Message Id: {}", data->messageIdNumber); - - // Terminate on error - if (static_cast(severity) == - vk::DebugUtilsMessageSeverityFlagBitsEXT::eError) { - Log::error(data->pMessage); - } else { - Log::warn(data->pMessage); - } - Log::warn(""); - return VK_FALSE; - } - - void Debugger::load_proxies(vk::Instance &instance) { - vk_create_debugger_dispatch = - reinterpret_cast( - instance.getProcAddr("vkCreateDebugUtilsMessengerEXT")); - vk_destroy_debugger_dispatch = - reinterpret_cast( - instance.getProcAddr("vkDestroyDebugUtilsMessengerEXT")); - } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Debugger.hpp b/src/Graphics/Vulkan/Core/Debugger.hpp deleted file mode 100644 index a1d8c2a5..00000000 --- a/src/Graphics/Vulkan/Core/Debugger.hpp +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include - -#include "../../../Log/Log.hpp" - -/** - * @brief API override for instancing the debug messenger. - * - * @param instance - * @param create_info - * @param allocator - * @param messenger - * @return VkResult - */ -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT( - VkInstance instance, - const VkDebugUtilsMessengerCreateInfoEXT *create_info, - const VkAllocationCallbacks *allocator, - VkDebugUtilsMessengerEXT *messenger); - -/** - * @brief API override for destroying the debug messenger. - * - * @param instance - * @param messenger - * @param allocator - */ -VKAPI_ATTR void VKAPI_CALL -vkDestroyDebugUtilsMessengerEXT(VkInstance instance, - VkDebugUtilsMessengerEXT messenger, - VkAllocationCallbacks const *allocator); - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Wrapper class for the Vulkan debugger extension. - * - */ - class Debugger { - vk::UniqueDebugUtilsMessengerEXT _messenger; - - /** - * @brief Message callback for error logging. - * - * @param severity - * @param type - * @param data - * @param user_data - * @return VKAPI_ATTR - */ - static VKAPI_ATTR VkBool32 VKAPI_CALL - message_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, - VkDebugUtilsMessageTypeFlagsEXT type, - VkDebugUtilsMessengerCallbackDataEXT const *data, - void *user_data); - - /** - * @brief Load the proxy functions for an instance. - * - * @param instance - */ - void load_proxies(vk::Instance &instance); - - public: - /** - * @brief Construct a new Debugger object. - * - * @param instance - */ - Debugger(vk::Instance &instance); - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/DescriptorPool.cpp b/src/Graphics/Vulkan/Core/DescriptorPool.cpp deleted file mode 100644 index e99ea682..00000000 --- a/src/Graphics/Vulkan/Core/DescriptorPool.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "./DescriptorPool.hpp" - -namespace Dynamo::Graphics::Vulkan { - DescriptorPool::DescriptorPool(Device &device) : _device(device) {} - - DescriptorPool::~DescriptorPool() { - for (const vk::DescriptorPool &pool : _pools) { - _device.get().get_handle().destroyDescriptorPool(pool); - } - } - - vk::DescriptorPool - DescriptorPool::create_pool(const vk::DescriptorSetLayout &layout, - const LayoutBindings &bindings) { - // Determine the pool sizes from the bindings associated with the layout - std::vector pool_sizes; - for (const vk::DescriptorSetLayoutBinding &binding : bindings) { - vk::DescriptorPoolSize pool_size; - pool_size.type = binding.descriptorType; - pool_size.descriptorCount = - MAX_DESCRIPTOR_SETS_PER_POOL * binding.descriptorCount; - pool_sizes.push_back(pool_size); - } - - vk::DescriptorPoolCreateInfo pool_info; - pool_info.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet; - pool_info.maxSets = MAX_DESCRIPTOR_SETS_PER_POOL; - pool_info.poolSizeCount = pool_sizes.size(); - pool_info.pPoolSizes = pool_sizes.data(); - - return _device.get().get_handle().createDescriptorPool(pool_info); - } - - DescriptorSetGroup - DescriptorPool::allocate_set(const vk::DescriptorSetLayout &layout, - const LayoutBindings &bindings, - const vk::DescriptorPool &pool, - Swapchain &swapchain) { - u32 image_count = swapchain.get_images().size(); - - // Allocate new descriptor sets within the pool - std::vector set_layouts(image_count, layout); - vk::DescriptorSetAllocateInfo alloc_info; - alloc_info.descriptorPool = pool; - alloc_info.descriptorSetCount = set_layouts.size(); - alloc_info.pSetLayouts = set_layouts.data(); - - return _device.get().get_handle().allocateDescriptorSetsUnique( - alloc_info); - } - - DescriptorSetGroup - DescriptorPool::try_allocate(const vk::DescriptorSetLayout &layout, - const LayoutBindings &bindings, - Swapchain &swapchain) { - b8 found_pool = false; - DescriptorSetGroup vksets; - for (vk::DescriptorPool &pool : _pools) { - try { - vksets = allocate_set(layout, bindings, pool, swapchain); - found_pool = true; - break; - } catch (vk::OutOfPoolMemoryError &err) { - continue; - } catch (vk::FragmentedPoolError &err) { - continue; - } - } - - // Create a new pool if no compatible one was found - if (!found_pool) { - vk::DescriptorPool pool = create_pool(layout, bindings); - _pools.push_back(pool); - vksets = allocate_set(layout, bindings, pool, swapchain); - } - return vksets; - } - - std::vector - DescriptorPool::allocate(PipelineLayout &pipeline_layout, - Swapchain &swapchain) { - const std::vector &layouts = - pipeline_layout.get_descriptor_set_layouts(); - const std::vector &bindings = - pipeline_layout.get_descriptor_set_bindings(); - - std::vector groups(layouts.size()); - for (u32 i = 0; i < layouts.size(); i++) { - groups.push_back(try_allocate(layouts[i], bindings[i], swapchain)); - } - return groups; - } - - void DescriptorPool::reset() { - // Reset all active descriptor pools and move them to the inactive queue - for (vk::DescriptorPool &pool : _pools) { - _device.get().get_handle().resetDescriptorPool(pool); - } - } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/DescriptorPool.hpp b/src/Graphics/Vulkan/Core/DescriptorPool.hpp deleted file mode 100644 index 84899631..00000000 --- a/src/Graphics/Vulkan/Core/DescriptorPool.hpp +++ /dev/null @@ -1,99 +0,0 @@ -#pragma once - -#include - -#include - -#include "../../../Types.hpp" -#include "./Device.hpp" -#include "./PipelineLayout.hpp" -#include "./Swapchain.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Group of descriptor sets. - * - */ - using DescriptorSetGroup = std::vector; - - /** - * @brief Maximum number of descriptor sets per pool. - * - */ - constexpr u32 MAX_DESCRIPTOR_SETS_PER_POOL = 1000; - - /** - * @brief Wrapper class abstraction over Vulkan descriptor pool. This - * allocates descriptor sets from a given pipeline layout. - * - */ - class DescriptorPool { - std::vector _pools; - std::reference_wrapper _device; - - /** - * @brief Create a new descriptor pool. - * - * @param layout Descriptor set layout - * @param bindings List of bindings for the layout - * @return vk::DescriptorPool - */ - vk::DescriptorPool create_pool(const vk::DescriptorSetLayout &layout, - const LayoutBindings &bindings); - - /** - * @brief Allocate descriptor sets for a given layout. - * - * @param layout Descriptor set layout - * @param bindings List of bindings for the layout - * @param pool Descriptor pool - * @return DescriptorSetGroup - */ - DescriptorSetGroup allocate_set(const vk::DescriptorSetLayout &layout, - const LayoutBindings &bindings, - const vk::DescriptorPool &pool, - Swapchain &swapchain); - - /** - * @brief Select a pool and allocate. - * - * @param layout - * @param bindings - * @return DescriptorSetGroup - */ - DescriptorSetGroup try_allocate(const vk::DescriptorSetLayout &layout, - const LayoutBindings &bindings, - Swapchain &swapchain); - - public: - /** - * @brief Construct a new DescriptorPool object. - * - * @param device Reference to the logical device - */ - DescriptorPool(Device &device); - - /** - * @brief Destroy the DescriptorPool object. - * - */ - ~DescriptorPool(); - - /** - * @brief Allocate descriptor sets grouped by layout and ordered by set - * index. - * - * @param pipeline_layout Reference to the pipeline layout - * @param swapchain Reference to the swapchain - * @return std::vector - */ - std::vector - allocate(PipelineLayout &pipeline_layout, Swapchain &swapchain); - - /** - * @brief Reset all descriptor pools. - * - */ - void reset(); - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Device.cpp b/src/Graphics/Vulkan/Core/Device.cpp deleted file mode 100644 index d2f1ccfe..00000000 --- a/src/Graphics/Vulkan/Core/Device.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "./Device.hpp" - -namespace Dynamo::Graphics::Vulkan { - Device::Device(PhysicalDevice &physical) : _physical(physical) { - // Get all unique queue families - auto cmp = [](QueueProperties a, QueueProperties b) { - return a.family_id != b.family_id; - }; - std::set unique_families(cmp); - unique_families.insert( - _physical.get_queue_properties(QueueFamily::Graphics)); - unique_families.insert( - _physical.get_queue_properties(QueueFamily::Transfer)); - unique_families.insert( - _physical.get_queue_properties(QueueFamily::Present)); - - // Allocate queues - std::vector queue_infos; - std::vector> priorities; - for (const QueueProperties &queue_properties : unique_families) { - // Priorities influence scheduling command buffer execution - priorities.emplace_back(queue_properties.count, 0.0f); - - vk::DeviceQueueCreateInfo queue_info; - queue_info.queueFamilyIndex = queue_properties.family_id; - queue_info.queueCount = queue_properties.count; - queue_info.pQueuePriorities = priorities.back().data(); - - queue_infos.push_back(queue_info); - } - - // Enable certain features of the physical device - vk::PhysicalDeviceFeatures device_features; - device_features.samplerAnisotropy = true; - device_features.sampleRateShading = true; - device_features.fillModeNonSolid = true; - - vk::PhysicalDeviceDescriptorIndexingFeatures descriptor_indexing; - descriptor_indexing.descriptorBindingPartiallyBound = true; - descriptor_indexing.runtimeDescriptorArray = true; - descriptor_indexing.descriptorBindingVariableDescriptorCount = true; - - // Create the logical device - auto &extensions = _physical.get_extensions(); - - vk::DeviceCreateInfo device_info; - device_info.queueCreateInfoCount = queue_infos.size(); - device_info.pQueueCreateInfos = queue_infos.data(); - device_info.enabledExtensionCount = extensions.size(); - device_info.ppEnabledExtensionNames = extensions.data(); - device_info.pEnabledFeatures = &device_features; - device_info.pNext = &descriptor_indexing; - - _handle = _physical.get_handle().createDevice(device_info); - } - - Device::~Device() { - wait(); - _handle.destroy(); - } - - const vk::Device &Device::get_handle() const { return _handle; } - - PhysicalDevice &Device::get_physical() { return _physical; } - - vk::Queue Device::get_queue(QueueFamily family, u32 index) { - QueueProperties properties = _physical.get_queue_properties(family); - return _handle.getQueue(properties.family_id, index); - } - - void Device::wait() { _handle.waitIdle(); } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Device.hpp b/src/Graphics/Vulkan/Core/Device.hpp deleted file mode 100644 index d8177860..00000000 --- a/src/Graphics/Vulkan/Core/Device.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include - -#include - -#include "../../../Types.hpp" -#include "./PhysicalDevice.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Wrapper class for a Vulkan logical device. This is the interface - * from which most Vulkan operations are performed to interact with the - * physical device. - * - */ - class Device { - vk::Device _handle; - PhysicalDevice _physical; - - public: - /** - * @brief Construct a new Device object. - * - * @param physical Physical device - */ - Device(PhysicalDevice &physical); - - /** - * @brief Destroy the Device object. - * - */ - ~Device(); - - /** - * @brief Get the handle to vk::Device. - * - * @return const vk::Device& - */ - const vk::Device &get_handle() const; - - /** - * @brief Get the physical device. - * - * @return PhysicalDevice& - */ - PhysicalDevice &get_physical(); - - /** - * @brief Get the graphics queue. - * - * @param family Class of commands handled by the queue - * @param index Queue index - * @return vk::Queue - */ - vk::Queue get_queue(QueueFamily family, u32 index = 0); - - /** - * @brief Wait for all queue operations to finish. - * - */ - void wait(); - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Fence.cpp b/src/Graphics/Vulkan/Core/Fence.cpp deleted file mode 100644 index 4cc892a7..00000000 --- a/src/Graphics/Vulkan/Core/Fence.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "./Fence.hpp" - -namespace Dynamo::Graphics::Vulkan { - Fence::Fence(Device &device) : _device(device) { - vk::FenceCreateInfo fence_info; - fence_info.flags = vk::FenceCreateFlagBits::eSignaled; - - _handle = _device.get().get_handle().createFence(fence_info); - } - - Fence::~Fence() { _device.get().get_handle().destroyFence(_handle); } - - const vk::Fence &Fence::get_handle() const { return _handle; } - - void Fence::wait(u64 timeout) { - vk::Result result = - _device.get().get_handle().waitForFences(_handle, true, timeout); - if (result != vk::Result::eSuccess) { - Log::error("An error occurred while waiting for Vulkan fence: {}", - vk::to_string(result)); - } - } - - b8 Fence::is_signaled() { - return _device.get().get_handle().getFenceStatus(_handle) == - vk::Result::eSuccess; - } - - void Fence::reset() { _device.get().get_handle().resetFences(_handle); } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Fence.hpp b/src/Graphics/Vulkan/Core/Fence.hpp deleted file mode 100644 index 2cfbea6e..00000000 --- a/src/Graphics/Vulkan/Core/Fence.hpp +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include - -#include "../../../Types.hpp" -#include "./Device.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Wrapper class of a Vulkan fence for CPU-GPU synchronization. - * - * When a command is sent to a queue, a fence can be signaled to tell the - * CPU that the GPU is currently at work. - * - * The CPU can then wait for that fence to finish before proceeding with - * its process. - * - */ - class Fence { - vk::Fence _handle; - std::reference_wrapper _device; - - public: - /** - * @brief Construct a new Fence object. - * - * @param device - */ - Fence(Device &device); - - /** - * @brief Destroy the Fence object. - * - */ - ~Fence(); - - /** - * @brief Get the handle to vk::Fence. - * - * @return const vk::Fence& - */ - const vk::Fence &get_handle() const; - - /** - * @brief Block the process until the fence finishes. - * - * @param timeout - */ - void wait(u64 timeout = UINT64_MAX); - - /** - * @brief Test if the fence is signaled. - * - * @return true - * @return false - */ - b8 is_signaled(); - - /** - * @brief Reset the fence. - * - */ - void reset(); - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Framebuffer.cpp b/src/Graphics/Vulkan/Core/Framebuffer.cpp deleted file mode 100644 index c68688a0..00000000 --- a/src/Graphics/Vulkan/Core/Framebuffer.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "./Framebuffer.hpp" - -namespace Dynamo::Graphics::Vulkan { - Framebuffer::Framebuffer(Device &device, - vk::Extent2D &extent, - RenderPass &renderpass, - ImageView &color_view, - ImageView &depth_view, - ImageView &swapchain_view) : - _device(device) { - std::array views = { - color_view.get_handle(), - depth_view.get_handle(), - swapchain_view.get_handle(), - }; - vk::FramebufferCreateInfo fb_info; - fb_info.renderPass = renderpass.get_handle(); - fb_info.attachmentCount = views.size(); - fb_info.pAttachments = views.data(); - fb_info.width = extent.width; - fb_info.height = extent.height; - fb_info.layers = 1; - - _handle = _device.get().get_handle().createFramebuffer(fb_info); - } - - Framebuffer::~Framebuffer() { - _device.get().get_handle().destroyFramebuffer(_handle); - } - - const vk::Framebuffer &Framebuffer::get_handle() const { return _handle; } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Framebuffer.hpp b/src/Graphics/Vulkan/Core/Framebuffer.hpp deleted file mode 100644 index 158e46a9..00000000 --- a/src/Graphics/Vulkan/Core/Framebuffer.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include - -#include "./Device.hpp" -#include "./Image.hpp" -#include "./ImageView.hpp" -#include "./RenderPass.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Wrapper class for a Vulkan Framebuffer. This maps image views to - * the attachments they represent. - * - */ - class Framebuffer { - vk::Framebuffer _handle; - std::reference_wrapper _device; - - public: - /** - * @brief Construct a new Framebuffer object. - * - * @param device Reference to the device - * @param extent Dimensions of the framebuffer - * @param renderpass Reference to the renderpass - * @param color_view Color buffer image view - * @param depth_view Depth buffer image view - * @param swapchain_view Swapchain image view - */ - Framebuffer(Device &device, - vk::Extent2D &extent, - RenderPass &renderpass, - ImageView &color_view, - ImageView &depth_view, - ImageView &swapchain_view); - - /** - * @brief Destroy the Framebuffer object. - * - */ - ~Framebuffer(); - - /** - * @brief Get the handle to vk::Framebuffer. - * - * @return const vk::Framebuffer& - */ - const vk::Framebuffer &get_handle() const; - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Image.cpp b/src/Graphics/Vulkan/Core/Image.cpp deleted file mode 100644 index cdd204db..00000000 --- a/src/Graphics/Vulkan/Core/Image.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "./Image.hpp" - -namespace Dynamo::Graphics::Vulkan { - Image::Image(Device &device, vk::Image handle, vk::Format format) : - _handle(handle), _device(device), _format(format) {} - - Image::Image(Device &device, - u32 width, - u32 height, - u32 depth, - u32 mip_levels, - u32 layer_count, - vk::Format format, - vk::ImageType type, - vk::ImageTiling tiling, - vk::ImageUsageFlags usage, - vk::SampleCountFlagBits samples) : - _device(device) { - vk::ImageCreateInfo image_info; - image_info.imageType = type; - image_info.format = format; - - image_info.extent.width = width; - image_info.extent.height = height; - image_info.extent.depth = depth; - - image_info.mipLevels = mip_levels; - image_info.arrayLayers = layer_count; - image_info.samples = samples; - - image_info.tiling = tiling; - image_info.usage = usage; - image_info.sharingMode = vk::SharingMode::eExclusive; - - _handle = device.get_handle().createImage(image_info); - _format = format; - } - - const vk::Image &Image::get_handle() const { return _handle; } - - Device &Image::get_device() { return _device.get(); } - - vk::Format Image::get_format() { return _format; } - - vk::MemoryRequirements Image::get_memory_requirements() const { - return _device.get().get_handle().getImageMemoryRequirements(_handle); - } - - UserImage::UserImage(Device &device, - MemoryPool &memory_pool, - u32 width, - u32 height, - u32 depth, - u32 mip_levels, - u32 layer_count, - vk::Format format, - vk::ImageType type, - vk::ImageTiling tiling, - vk::ImageUsageFlags usage, - vk::SampleCountFlagBits samples) : - Image(device, - width, - height, - depth, - mip_levels, - layer_count, - format, - type, - tiling, - usage, - samples), - _block(memory_pool.allocate(get_memory_requirements(), - vk::MemoryPropertyFlagBits::eDeviceLocal)) { - _block.bind(_handle); - } - - UserImage::~UserImage() { - _device.get().get_handle().destroyImage(_handle); - } - - SwapchainImage::SwapchainImage(Device &device, - vk::Image handle, - vk::Format format) : - Image(device, handle, format) {} - - SwapchainImage::~SwapchainImage() {} -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Image.hpp b/src/Graphics/Vulkan/Core/Image.hpp deleted file mode 100644 index 65770754..00000000 --- a/src/Graphics/Vulkan/Core/Image.hpp +++ /dev/null @@ -1,156 +0,0 @@ -#pragma once - -#include - -#include - -#include "../../../Types.hpp" -#include "./Device.hpp" -#include "./MemoryPool.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Abstract base wrapper class for a Vulkan image. - * - */ - class Image { - protected: - vk::Image _handle; - std::reference_wrapper _device; - vk::Format _format; - - public: - /** - * @brief Construct a new Image object from an existing handle. - * - * @param device Reference to the logical device - * @param handle Vulkan image handle - * @param format Pixel format - */ - Image(Device &device, vk::Image handle, vk::Format format); - - /** - * @brief Construct a new Image object with parameters. - * - * @param device Reference to the logical device - * @param width Width of the image - * @param height Height of the image - * @param depth Depth of the image (3D texture) - * @param mip_levels Number of mipmap levels - * @param layer_count Number of array layers - * @param format Pixel format - * @param type 1D, 2D, or 3D - * @param tiling Tiling mode of the texels in-memory - * @param usage Usage flags - * @param samples MSAA sample count - */ - Image(Device &device, - u32 width, - u32 height, - u32 depth, - u32 mip_levels, - u32 layer_count, - vk::Format format, - vk::ImageType type, - vk::ImageTiling tiling, - vk::ImageUsageFlags usage, - vk::SampleCountFlagBits samples); - virtual ~Image() = 0; - - /** - * @brief Get the handle to vk::Image. - * - * @return const vk::Image& - */ - const vk::Image &get_handle() const; - - /** - * @brief Get the device. - * - * @return Device& - */ - Device &get_device(); - - /** - * @brief Get the format object. - * - * @return vk::Format - */ - vk::Format get_format(); - - /** - * @brief Get the memory requirements for the image. - * - * @return vk::MemoryRequirements - */ - vk::MemoryRequirements get_memory_requirements() const; - }; - inline Image::~Image() = default; - - /** - * @brief User-created image. - * - */ - class UserImage : public Image { - MemoryBlock _block; - - public: - /** - * @brief Construct a new UserImage object. - * - * @param device Reference to the logical device - * @param memory_pool Reference to the memory pool - * @param width Width of the image - * @param height Height of the image - * @param depth Depth of the image (3D texture) - * @param mip_levels Number of mipmap levels - * @param layer_count Number of array layers - * @param format Pixel format - * @param type 1D, 2D, or 3D - * @param tiling Tiling mode of the texels in-memory - * @param usage Usage flags - * @param samples MSAA sample count - */ - UserImage(Device &device, - MemoryPool &memory_pool, - u32 width, - u32 height, - u32 depth, - u32 mip_levels, - u32 layer_count, - vk::Format format, - vk::ImageType type, - vk::ImageTiling tiling, - vk::ImageUsageFlags usage, - vk::SampleCountFlagBits samples); - - /** - * @brief Destroy the UserImage object. - * - */ - ~UserImage(); - }; - - /** - * @brief Swapchain images are a special case because they are owned by the - * Vulkan instance, and so they cannot be manually destroyed. - * - */ - class SwapchainImage : public Image { - public: - /** - * @brief Construct a new SwapchainImage object. - * - * @param device Reference to the logical device - * @param handle Vulkan image handle - * @param format Pixel format - */ - SwapchainImage(Device &device, vk::Image handle, vk::Format format); - - /** - * @brief Destroy the SwapchainImage object (do nothing). - * - */ - ~SwapchainImage(); - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/ImageView.cpp b/src/Graphics/Vulkan/Core/ImageView.cpp deleted file mode 100644 index 821270eb..00000000 --- a/src/Graphics/Vulkan/Core/ImageView.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "./ImageView.hpp" - -namespace Dynamo::Graphics::Vulkan { - ImageView::ImageView(Image &image, - vk::ImageViewType type, - vk::ImageAspectFlags aspect_mask, - u32 mip_levels, - u32 layer_count) : - _image(image) { - vk::ImageViewCreateInfo view_info; - view_info.image = image.get_handle(); - view_info.format = image.get_format(); - view_info.viewType = type; - - view_info.subresourceRange.aspectMask = aspect_mask; - view_info.subresourceRange.baseMipLevel = 0; - view_info.subresourceRange.levelCount = mip_levels; - view_info.subresourceRange.baseArrayLayer = 0; - view_info.subresourceRange.layerCount = layer_count; - - _handle = image.get_device().get_handle().createImageView(view_info); - } - - ImageView::~ImageView() { - _image.get().get_device().get_handle().destroyImageView(_handle); - } - - const vk::ImageView &ImageView::get_handle() const { return _handle; } - - Image &ImageView::get_image() { return _image.get(); } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/ImageView.hpp b/src/Graphics/Vulkan/Core/ImageView.hpp deleted file mode 100644 index 1b7b1bc8..00000000 --- a/src/Graphics/Vulkan/Core/ImageView.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include - -#include - -#include "../../../Types.hpp" -#include "./Device.hpp" -#include "./Image.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Wrapper class for a Vulkan image view. This is a portion of the - * image that can be accessed (e.g., by the pipeline) and also describes how - * it should be accessed. - * - */ - class ImageView { - vk::ImageView _handle; - std::reference_wrapper _image; - - public: - /** - * @brief Construct a new ImageView object. - * - * @param image Reference to the main image - * @param type 1D, 2D, or 3D - * @param aspect_mask Aspect of the pixel format to access - * @param mip_levels Number of mipmap levels - * @param layer_count Number of layers - */ - ImageView(Image &image, - vk::ImageViewType type, - vk::ImageAspectFlags aspect_mask, - u32 mip_levels, - u32 layer_count = 1); - - /** - * @brief Destroy the ImageView object. - * - */ - ~ImageView(); - - /** - * @brief Get the handle to vk::ImageView. - * - * @return const vk::ImageView& - */ - const vk::ImageView &get_handle() const; - - /** - * @brief Get a reference to the main image. - * - * @return Image& - */ - Image &get_image(); - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Memory.cpp b/src/Graphics/Vulkan/Core/Memory.cpp deleted file mode 100644 index 83c71cd9..00000000 --- a/src/Graphics/Vulkan/Core/Memory.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "./Memory.hpp" - -namespace Dynamo::Graphics::Vulkan { - Memory::Memory(Device &device, - vk::MemoryRequirements requirements, - vk::MemoryPropertyFlags properties) : - _device(device), - _allocator(requirements.size) { - // Find the appropriate type index - const vk::PhysicalDeviceMemoryProperties &physical_memory = - _device.get().get_physical().get_memory_properties(); - u32 index; - for (index = 0; index < physical_memory.memoryTypeCount; index++) { - _type = physical_memory.memoryTypes[index]; - if ((requirements.memoryTypeBits & (1 << index)) && - ((_type.propertyFlags & properties) == properties)) { - break; - } - } - - // Allocate the memory - vk::MemoryAllocateInfo alloc_info; - alloc_info.allocationSize = requirements.size; - alloc_info.memoryTypeIndex = index; - - _handle = _device.get().get_handle().allocateMemory(alloc_info); - _capacity = requirements.size; - - // Map memory once if possible - if (properties & vk::MemoryPropertyFlagBits::eHostVisible) { - _mapped = reinterpret_cast( - _device.get().get_handle().mapMemory(_handle, 0, _capacity)); - } else { - _mapped = nullptr; - } - } - - Memory::~Memory() { - if (_mapped != nullptr) { - _device.get().get_handle().unmapMemory(_handle); - } - _device.get().get_handle().freeMemory(_handle); - } - - const vk::DeviceMemory &Memory::get_handle() const { return _handle; } - - const vk::MemoryType &Memory::get_type() const { return _type; } - - Device &Memory::get_device() { return _device; } - - u32 Memory::get_capacity() const { return _capacity; } - - void Memory::read(i8 *dst, u32 offset, u32 length) { - DYN_ASSERT(_mapped != nullptr); - DYN_ASSERT(offset + length <= _capacity); - std::memcpy(dst, _mapped + offset, length); - } - - void Memory::write(i8 *src, u32 offset, u32 length) { - DYN_ASSERT(_mapped != nullptr); - DYN_ASSERT(offset + length <= _capacity); - std::memcpy(_mapped + offset, src, length); - } - - void Memory::bind(vk::Image vkimage, u32 offset) { - _device.get().get_handle().bindImageMemory(vkimage, _handle, offset); - } - - void Memory::bind(vk::Buffer vkbuffer, u32 offset) { - _device.get().get_handle().bindBufferMemory(vkbuffer, _handle, offset); - } - - std::optional Memory::reserve(u32 size, u32 alignment) { - return _allocator.reserve(size, alignment); - } - - void Memory::free(u32 offset) { return _allocator.free(offset); } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Memory.hpp b/src/Graphics/Vulkan/Core/Memory.hpp deleted file mode 100644 index bfb1e2c1..00000000 --- a/src/Graphics/Vulkan/Core/Memory.hpp +++ /dev/null @@ -1,126 +0,0 @@ -#pragma once - -#include -#include -#include - -#include - -#include "../../../Log/Log.hpp" -#include "../../../Types.hpp" -#include "../../../Utils/Allocator.hpp" -#include "./Device.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Wrapper class for Vulkan device memory. - * - */ - class Memory { - vk::DeviceMemory _handle; - std::reference_wrapper _device; - Allocator _allocator; - - vk::MemoryType _type; - u32 _capacity; - - i8 *_mapped; - - public: - /** - * @brief Construct a new Memory object. - * - * @param device Reference to the logical device - * @param requirements Memory allocation requirements - * @param properties Memory properties - */ - Memory(Device &device, - vk::MemoryRequirements requirements, - vk::MemoryPropertyFlags properties); - - /** - * @brief Destroy the Memory object. - * - */ - ~Memory(); - - /** - * @brief Get the handle to vk::DeviceMemory. - * - * @return const vk::DeviceMemory& - */ - const vk::DeviceMemory &get_handle() const; - - /** - * @brief Get the memory type. - * - * @return const vk::MemoryType& - */ - const vk::MemoryType &get_type() const; - - /** - * @brief Get the device. - * - * @return Device& - */ - Device &get_device(); - - /** - * @brief Get the total capacity of the memory. - * - * @return u32 - */ - u32 get_capacity() const; - - /** - * @brief Read from mapped memory. - * - * @param dst Destination buffer - * @param offset Offset within the memory map in bytes - * @param length Length of the read in bytes - */ - void read(i8 *dst, u32 offset, u32 length); - - /** - * @brief Write to mapped memory. - * - * @param src Source buffer - * @param offset Offset within the memory map in bytes - * @param length Length of the write in bytes - */ - void write(i8 *src, u32 offset, u32 length); - - /** - * @brief Bind a vk::Image to the underlying vk::Memory. - * - * @param vkimage Handle to vk::Image - * @param offset Offset within the memory map in bytes - */ - void bind(vk::Image vkimage, u32 offset); - - /** - * @brief Bind a vk::Buffer to the underlying vk::Memory. - * - * @param vkbuffer Handle to vk::Buffer - * @param offset Offset within the memory map in bytes - */ - void bind(vk::Buffer vkbuffer, u32 offset); - - /** - * @brief Reserve a block of memory with specific alignment - * requirements, returning the offset within the pool. - * - * @param size Desired size in bytes - * @param alignment Alignment requirement in bytes - * @return std::optional - */ - std::optional reserve(u32 size, u32 alignment); - - /** - * @brief Free the block of reserved memory at an offset. - * - * @param offset Offset within the pool in bytes returned by reserve() - */ - void free(u32 offset); - }; -} // namespace Dynamo::Graphics::Vulkan diff --git a/src/Graphics/Vulkan/Core/MemoryPool.cpp b/src/Graphics/Vulkan/Core/MemoryPool.cpp deleted file mode 100644 index 8c291c52..00000000 --- a/src/Graphics/Vulkan/Core/MemoryPool.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include "./MemoryPool.hpp" - -namespace Dynamo::Graphics::Vulkan { - MemoryBlock::MemoryBlock(Memory &memory, u32 offset, u32 size) : - _memory(memory), _offset(offset), _size(size), _moved(false) {} - - MemoryBlock::MemoryBlock(MemoryBlock &&rhs) : - _memory(rhs._memory), _offset(rhs._offset), _size(rhs._size) { - rhs._moved = true; - } - - MemoryBlock::~MemoryBlock() { - if (!_moved) { - _memory.get().free(_offset); - } - } - - const vk::DeviceMemory &MemoryBlock::get_handle() const { - DYN_ASSERT(!_moved); - return _memory.get().get_handle(); - } - - u32 MemoryBlock::offset() const { - DYN_ASSERT(!_moved); - return _offset; - } - - u32 MemoryBlock::size() const { - DYN_ASSERT(!_moved); - return _size; - } - - void MemoryBlock::read(i8 *dst, u32 offset, u32 length) { - DYN_ASSERT(!_moved); - _memory.get().read(dst, offset + _offset, length); - } - - void MemoryBlock::write(i8 *src, u32 offset, u32 length) { - DYN_ASSERT(!_moved); - _memory.get().write(src, offset + _offset, length); - } - - void MemoryBlock::bind(vk::Image vkimage) { - DYN_ASSERT(!_moved); - _memory.get().bind(vkimage, _offset); - } - - void MemoryBlock::bind(vk::Buffer vkbuffer) { - DYN_ASSERT(!_moved); - _memory.get().bind(vkbuffer, _offset); - } - - MemoryPool::MemoryPool(Device &device) : _device(device) {} - - b8 MemoryPool::is_compatible(Memory &memory, - vk::MemoryRequirements requirements, - vk::MemoryPropertyFlags properties) { - const vk::PhysicalDeviceMemoryProperties &physical_memory = - _device.get().get_physical().get_memory_properties(); - u32 index; - for (index = 0; index < physical_memory.memoryTypeCount; index++) { - vk::MemoryType type = physical_memory.memoryTypes[index]; - if ((requirements.memoryTypeBits & (1 << index)) && - (memory.get_type() == type) && - ((type.propertyFlags & properties) == properties)) { - return true; - } - } - return false; - } - - MemoryBlock MemoryPool::allocate(vk::MemoryRequirements requirements, - vk::MemoryPropertyFlags properties) { - // Look for an existing compatible pool - for (std::unique_ptr &memory : _pools) { - if (is_compatible(*memory, requirements, properties)) { - std::optional result = - memory.get()->reserve(requirements.size, - requirements.alignment); - if (result.has_value()) { - return MemoryBlock(std::ref(*memory), - result.value(), - requirements.size); - } - } - } - - // Create a new memory pool - vk::MemoryRequirements alloc_requirements; - alloc_requirements.size = - std::max(align_size(requirements.size, requirements.alignment), - MINIMUM_MEMORY_CAPACITY); - alloc_requirements.memoryTypeBits = requirements.memoryTypeBits; - - _pools.push_back(std::make_unique(_device.get(), - alloc_requirements, - properties)); - std::unique_ptr &memory = _pools.back(); - - // Allocate memory - std::optional result = - memory.get()->reserve(requirements.size, requirements.alignment); - if (!result.has_value()) { - Log::error("Unable to allocate Vulkan memory"); - } - return MemoryBlock(std::ref(*memory), - result.value(), - requirements.size); - } - - void MemoryBlock::operator=(MemoryBlock &&rhs) { - _memory = rhs._memory; - _offset = rhs._offset; - _size = rhs._size; - rhs._moved = true; - } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/MemoryPool.hpp b/src/Graphics/Vulkan/Core/MemoryPool.hpp deleted file mode 100644 index 38941d9a..00000000 --- a/src/Graphics/Vulkan/Core/MemoryPool.hpp +++ /dev/null @@ -1,164 +0,0 @@ -#pragma once - -#include -#include -#include - -#include - -#include "../../../Types.hpp" -#include "../../../Utils/Bits.hpp" -#include "./Device.hpp" -#include "./Memory.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Minimum capacity of a Memory object. - * - */ - constexpr u32 MINIMUM_MEMORY_CAPACITY = 256 * (1 << 20); - - /** - * @brief MemoryBlock exposes a similar interface to Memory for managing an - * underlying block of memory at an offset. However, it is similar to - * std::unique_ptr in that it can only be moved and not copied. - * - */ - class MemoryBlock { - std::reference_wrapper _memory; - u32 _offset; - u32 _size; - - b8 _moved; - - public: - /** - * @brief Construct a new MemoryBlock object. - * - * @param memory Reference to the memory - * @param offset Reserved block offset in bytes - * @param size Reserved block size in bytes - */ - MemoryBlock(Memory &memory, u32 offset, u32 size); - - /** - * @brief Move constructor. - * - * @param rhs - */ - MemoryBlock(MemoryBlock &&rhs); - - /** - * @brief Destroy the MemoryBlock object. - * - */ - ~MemoryBlock(); - - /** - * @brief Get the handle to vk::DeviceMemory. - * - * @return const vk::DeviceMemory& - */ - const vk::DeviceMemory &get_handle() const; - - /** - * @brief Get the offset. - * - * @return u32 - */ - u32 offset() const; - - /** - * @brief Get the size of the allocation. - * - * @return u32 - */ - u32 size() const; - - /** - * @brief Read from the underlying memory at an offset. - * - * @param dst Destination buffer - * @param offset Offset within the memory map in bytes - * @param length Length of the read in bytes - */ - void read(i8 *dst, u32 offset, u32 length); - - /** - * @brief Write to the underlying memory at an offset. - * - * @param dst Source buffer - * @param offset Offset within the memory map in bytes - * @param length Length of the read in bytes - */ - void write(i8 *src, u32 offset, u32 length); - - /** - * @brief Bind a vk::Image to the block. - * - * @param vkimage - */ - void bind(vk::Image vkimage); - - /** - * @brief Bind a vk::Buffer to the block. - * - * @param vkbuffer - */ - void bind(vk::Buffer vkbuffer); - - /** - * @brief Move assignment operator. - * - * @param rhs - */ - void operator=(MemoryBlock &&rhs); - }; - - /** - * @brief Dynamic memory pool. - * - * Memory objects are grouped based on their type so allocations with - * desired properties can be queried. - * - */ - class MemoryPool { - std::reference_wrapper _device; - - using Pool = std::vector>; - Pool _pools; - - /** - * @brief Check if a memory pool is compatible with the given - * requirements and properties. - * - * @param memory - * @param requirements - * @param properties - * @return true - * @return false - */ - b8 is_compatible(Memory &memory, - vk::MemoryRequirements requirements, - vk::MemoryPropertyFlags properties); - - public: - /** - * @brief Construct a new MemoryPool object. - * - * @param device Reference to the logical device - */ - MemoryPool(Device &device); - - /** - * @brief Allocate a block of memory with specific requirements and - * properties. - * - * @param requirements Memory requirements - * @param properties Memory properties - * @return Allocation - */ - MemoryBlock allocate(vk::MemoryRequirements requirements, - vk::MemoryPropertyFlags properties); - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/PhysicalDevice.cpp b/src/Graphics/Vulkan/Core/PhysicalDevice.cpp deleted file mode 100644 index a5d1647a..00000000 --- a/src/Graphics/Vulkan/Core/PhysicalDevice.cpp +++ /dev/null @@ -1,205 +0,0 @@ -#include "./PhysicalDevice.hpp" - -namespace Dynamo::Graphics::Vulkan { - PhysicalDevice::PhysicalDevice(vk::PhysicalDevice handle, - vk::SurfaceKHR surface) { - _handle = handle; - _surface = surface; - - _properties = _handle.getProperties(); - _memory_properties = _handle.getMemoryProperties(); - _features = _handle.getFeatures(); - - // Add the extensions required by all devices - _extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); - - // Enable portability subset extension if available - const i8 *portability_ext = "VK_KHR_portability_subset"; - for (vk::ExtensionProperties &ext : - _handle.enumerateDeviceExtensionProperties()) { - if (!std::strcmp(ext.extensionName, portability_ext)) { - _extensions.push_back(portability_ext); - } - } - - enumerate_command_queues(); - get_swapchain_options(); - } - - b8 PhysicalDevice::is_complete() const { - return _graphics_queue_properties.count > 0 && - _present_queue_properties.count > 0 && - _transfer_queue_properties.count > 0; - } - - b8 PhysicalDevice::is_supporting_extensions() const { - auto available = _handle.enumerateDeviceExtensionProperties(); - std::unordered_set required(_extensions.begin(), - _extensions.end()); - - for (vk::ExtensionProperties &extension : available) { - required.erase(extension.extensionName); - } - return required.empty(); - } - - b8 PhysicalDevice::is_supporting_swapchain() const { - return !_swapchain_options.formats.empty() && - !_swapchain_options.present_modes.empty(); - } - - void PhysicalDevice::enumerate_command_queues() { - auto families = _handle.getQueueFamilyProperties(); - u32 index = 0; - for (vk::QueueFamilyProperties &family : families) { - // Dedicated presentation queue - if (_handle.getSurfaceSupportKHR(index, _surface)) { - _present_queue_properties.family_id = index; - _present_queue_properties.count = family.queueCount; - } - - // Dedicated graphics queue - if (family.queueFlags & vk::QueueFlagBits::eGraphics) { - _graphics_queue_properties.family_id = index; - _graphics_queue_properties.count = family.queueCount; - } - - // Dedicated transfer queue - if (family.queueFlags & vk::QueueFlagBits::eTransfer) { - _transfer_queue_properties.family_id = index; - _transfer_queue_properties.count = family.queueCount; - } - - if (is_complete()) { - break; - } - index++; - } - - // If the graphics and transfer queues are not available, use the - // presentation queue - if (_graphics_queue_properties.count == 0) { - _graphics_queue_properties = _present_queue_properties; - } - if (_transfer_queue_properties.count == 0) { - _transfer_queue_properties = _present_queue_properties; - } - } - - const vk::PhysicalDevice &PhysicalDevice::get_handle() const { - return _handle; - } - - const std::string PhysicalDevice::get_name() const { - return _properties.deviceName; - } - - const std::vector &PhysicalDevice::get_extensions() const { - return _extensions; - } - - const SwapchainOptions &PhysicalDevice::get_swapchain_options() { - _swapchain_options = { - _handle.getSurfaceCapabilitiesKHR(_surface), - _handle.getSurfaceFormatsKHR(_surface), - _handle.getSurfacePresentModesKHR(_surface), - }; - return _swapchain_options; - } - - const QueueProperties & - PhysicalDevice::get_queue_properties(QueueFamily family) const { - switch (family) { - case QueueFamily::Graphics: - return _graphics_queue_properties; - break; - case QueueFamily::Transfer: - return _transfer_queue_properties; - break; - case QueueFamily::Present: - default: - return _present_queue_properties; - break; - } - } - - vk::FormatProperties - PhysicalDevice::get_format_properties(vk::Format format) const { - return _handle.getFormatProperties(format); - } - - const vk::PhysicalDeviceMemoryProperties & - PhysicalDevice::get_memory_properties() const { - return _memory_properties; - } - - const vk::PhysicalDeviceLimits &PhysicalDevice::get_limits() const { - return _properties.limits; - } - - vk::SampleCountFlagBits PhysicalDevice::get_msaa_samples() const { - vk::SampleCountFlags counts = - _properties.limits.framebufferColorSampleCounts; - - // Get the maximum available sample count for improved visuals - if (counts & vk::SampleCountFlagBits::e64) - return vk::SampleCountFlagBits::e64; - if (counts & vk::SampleCountFlagBits::e32) - return vk::SampleCountFlagBits::e32; - if (counts & vk::SampleCountFlagBits::e16) - return vk::SampleCountFlagBits::e16; - if (counts & vk::SampleCountFlagBits::e8) - return vk::SampleCountFlagBits::e8; - if (counts & vk::SampleCountFlagBits::e4) - return vk::SampleCountFlagBits::e4; - if (counts & vk::SampleCountFlagBits::e2) - return vk::SampleCountFlagBits::e2; - return vk::SampleCountFlagBits::e1; - } - - vk::Format PhysicalDevice::get_depth_format() const { - std::array query = {vk::Format::eD32Sfloat, - vk::Format::eD32SfloatS8Uint, - vk::Format::eD24UnormS8Uint}; - vk::ImageTiling tiling = vk::ImageTiling::eOptimal; - vk::FormatFeatureFlags format_flags = - vk::FormatFeatureFlagBits::eDepthStencilAttachment; - - // Find a format that satisfies the feature requirements - for (vk::Format &format : query) { - vk::FormatProperties properties = get_format_properties(format); - if (tiling == vk::ImageTiling::eLinear && - (properties.linearTilingFeatures & format_flags) == - format_flags) { - return format; - } else if (tiling == vk::ImageTiling::eOptimal && - (properties.optimalTilingFeatures & format_flags) == - format_flags) { - return format; - } - } - Log::error("Vulkan failed to find a suitable pixel format for the " - "depth buffer."); - return query[0]; - } - - i32 PhysicalDevice::calculate_score() const { - i32 score = 0; - - // Ensure all necessary features are present - if (!is_complete() || !is_supporting_extensions() || - !is_supporting_swapchain() || !_features.samplerAnisotropy) { - return 0; - } - - // Dedicated GPU are prioritized - vk::PhysicalDeviceType discrete = vk::PhysicalDeviceType::eDiscreteGpu; - if (_properties.deviceType == discrete) { - score += 1000; - } - - // What is the largest image that can be stored in VRAM? - score += _properties.limits.maxImageDimension2D; - return score; - } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/PhysicalDevice.hpp b/src/Graphics/Vulkan/Core/PhysicalDevice.hpp deleted file mode 100644 index 5a80eaeb..00000000 --- a/src/Graphics/Vulkan/Core/PhysicalDevice.hpp +++ /dev/null @@ -1,224 +0,0 @@ -#pragma once - -#include -#include -#include - -#include - -#include "../../../Log/Log.hpp" -#include "../../../Types.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Enumerates the different queue families. - * - */ - enum class QueueFamily : u32 { - /** - * @brief Graphics commands. - * - */ - Graphics, - - /** - * @brief Buffer transfer commands. - * - */ - Transfer, - - /** - * @brief Presentation commands. - * - */ - Present - }; - - /** - * @brief Properties of a command queue. - * - */ - struct QueueProperties { - /** - * @brief Family identifier. - * - */ - u32 family_id = 0; - - /** - * @brief Number of available queues. - * - */ - u32 count = 0; - }; - - /** - * @brief Available options for creating a swapchain. - * - */ - struct SwapchainOptions { - /** - * @brief Surface capabilities. - * - */ - vk::SurfaceCapabilitiesKHR capabilities; - - /** - * @brief Pixel formats and color spaces. - * - */ - std::vector formats; - - /** - * @brief Presentation modes - * - */ - std::vector present_modes; - }; - - /** - * @brief Wrapper class for a Vulkan physical device. This allows querying - * the different properties of the graphics hardware. - * - */ - class PhysicalDevice { - vk::PhysicalDevice _handle; - vk::SurfaceKHR _surface; - - vk::PhysicalDeviceProperties _properties; - vk::PhysicalDeviceMemoryProperties _memory_properties; - vk::PhysicalDeviceFeatures _features; - - SwapchainOptions _swapchain_options; - - QueueProperties _graphics_queue_properties; - QueueProperties _present_queue_properties; - QueueProperties _transfer_queue_properties; - - std::vector _extensions; - - /** - * @brief Check if the device contains the required queue families. - * - * @return true - * @return false - */ - b8 is_complete() const; - - /** - * @brief Check if the device supports the required extensions. - * - * @return true - * @return false - */ - b8 is_supporting_extensions() const; - - /** - * @brief Check if the device supports swapchaining. - * - * @return true - * @return false - */ - b8 is_supporting_swapchain() const; - - /** - * @brief Enumerate the available queue familes. - * - */ - void enumerate_command_queues(); - - public: - /** - * @brief Construct a new Physical object. - * - * @param handle Vulkan PhysicalDevice handle - * @param surface Vulkan window surface - */ - PhysicalDevice(vk::PhysicalDevice handle, vk::SurfaceKHR surface); - - /** - * @brief Get the handle object to the vk::PhysicalDevice. - * - * @return const vk::PhysicalDevice& - */ - const vk::PhysicalDevice &get_handle() const; - - /** - * @brief Get the name of the device. - * - * @return std::string - */ - const std::string get_name() const; - - /** - * @brief Get the extensions list. - * - * @return const std::vector& - */ - const std::vector &get_extensions() const; - - /** - * @brief Get the available options for the swapchain. - * - * @return const SwapchainOptions& - */ - const SwapchainOptions &get_swapchain_options(); - - /** - * @brief Get the properties of a queue. - * - * @return const QueueProperties& - */ - - /** - * @brief Get the properties of a queue. - * - * @param family Class of commands handled by the queue - * @return const QueueProperties& - */ - const QueueProperties &get_queue_properties(QueueFamily family) const; - - /** - * @brief Get the properties of a pixel format. - * - * @param format Pixel format - * @return vk::FormatProperties - */ - vk::FormatProperties get_format_properties(vk::Format format) const; - - /** - * @brief Get the memory properties of the hardware. - * - * @return const vk::PhysicalDeviceMemoryProperties - */ - const vk::PhysicalDeviceMemoryProperties &get_memory_properties() const; - - /** - * @brief Get the limits of the device. - * - * @return const vk::PhysicalDeviceLimits& - */ - const vk::PhysicalDeviceLimits &get_limits() const; - - /** - * @brief Get the anti-aliasing sample count supported by the device. - * - * @return vk::SampleCountFlagBits - */ - vk::SampleCountFlagBits get_msaa_samples() const; - - /** - * @brief Get the supported pixel format for the depth buffer. - * - * @return vk::Format - */ - vk::Format get_depth_format() const; - - /** - * @brief Calculate heuristic for selecting the best device. - * - * @return i32 - */ - i32 calculate_score() const; - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Pipeline.cpp b/src/Graphics/Vulkan/Core/Pipeline.cpp deleted file mode 100644 index 0a8f1a8d..00000000 --- a/src/Graphics/Vulkan/Core/Pipeline.cpp +++ /dev/null @@ -1,188 +0,0 @@ -#include "./Pipeline.hpp" - -namespace Dynamo::Graphics::Vulkan { - Pipeline::Pipeline(Device &device, - RenderPass &renderpass, - Swapchain &swapchain, - PipelineLayout &layout, - vk::PrimitiveTopology primitive_topology, - vk::PolygonMode polygon_mode) : - _device(device) { - create_vertex_input_state(); - create_assembly_state(primitive_topology); - create_viewport_state(swapchain.get_extent()); - create_rasterization_state(polygon_mode); - create_multisampler_state(); - create_depth_stencil_state(); - create_blender_state(); - create_dynamic_state(); - - vk::GraphicsPipelineCreateInfo pipeline_info; - - // Assembly stages - pipeline_info.pVertexInputState = &_vertex_input_state_info; - pipeline_info.pInputAssemblyState = &_assembly_state_info; - - // Fixed function stages - pipeline_info.pViewportState = &_viewport_state_info; - pipeline_info.pRasterizationState = &_rasterization_state_info; - pipeline_info.pMultisampleState = &_multisampler_state_info; - pipeline_info.pDepthStencilState = &_depth_stencil_state_info; - pipeline_info.pColorBlendState = &_blender_state_info; - pipeline_info.pDynamicState = &_dynamic_state_info; - - // Programmable shader stages - std::vector shader_modules; - std::vector shader_stage_infos; - const ShaderList &shaders = layout.get_shaders(); - for (u32 i = 0; i < shaders.size(); i++) { - shader_modules.push_back(shaders[i].get().get_handle()); - shader_stage_infos.push_back( - create_shader_stage(shader_modules[i].get(), - shaders[i].get().get_stage())); - } - pipeline_info.stageCount = shader_stage_infos.size(); - pipeline_info.pStages = shader_stage_infos.data(); - - // Layout and render pass - pipeline_info.layout = layout.get_handle(); - pipeline_info.renderPass = renderpass.get_handle(); - pipeline_info.subpass = 0; // Subpass index where it is used - - // Derived pipeline? - pipeline_info.basePipelineHandle = nullptr; - pipeline_info.basePipelineIndex = 0; - - vk::ResultValue result = - _device.get().get_handle().createGraphicsPipeline( - nullptr, // TODO: Pipeline cache - pipeline_info); - _handle = result.value; - } - - Pipeline::~Pipeline() { - _device.get().get_handle().destroyPipeline(_handle); - } - - vk::PipelineShaderStageCreateInfo - Pipeline::create_shader_stage(vk::ShaderModule module, - vk::ShaderStageFlagBits stage) { - vk::PipelineShaderStageCreateInfo shader_stage; - shader_stage.module = module; - shader_stage.stage = stage; - shader_stage.pName = "main"; // Entry function - - return shader_stage; - } - - void Pipeline::create_vertex_input_state() { - _vertex_input_state_info.vertexBindingDescriptionCount = 1; - _vertex_input_state_info.pVertexBindingDescriptions = - &VERTEX_BINDING_DESCRIPTION; - _vertex_input_state_info.vertexAttributeDescriptionCount = - VERTEX_ATTRIBUTE_DESCRIPTIONS.size(); - _vertex_input_state_info.pVertexAttributeDescriptions = - VERTEX_ATTRIBUTE_DESCRIPTIONS.data(); - } - - void - Pipeline::create_assembly_state(vk::PrimitiveTopology primitive_topology) { - _assembly_state_info.topology = primitive_topology; - _assembly_state_info.primitiveRestartEnable = false; - } - - void Pipeline::create_viewport_state(const vk::Extent2D &extent) { - // Origin - _viewport.x = 0.0f; - _viewport.y = 0.0f; - - // Dimensions - _viewport.width = extent.width; - _viewport.height = extent.height; - - // Render depth range - _viewport.minDepth = 0.0f; - _viewport.maxDepth = 1.0f; - - // Subsection of the viewport to be used - _scissor.offset.x = 0; - _scissor.offset.y = 0; - _scissor.extent = extent; - - _viewport_state_info.viewportCount = 1; - _viewport_state_info.pViewports = &_viewport; - _viewport_state_info.scissorCount = 1; - _viewport_state_info.pScissors = &_scissor; - } - - void Pipeline::create_rasterization_state(vk::PolygonMode polygon_mode) { - _rasterization_state_info.depthClampEnable = false; - _rasterization_state_info.rasterizerDiscardEnable = false; - - // How to draw polygon - // * eFill - Standard - // * eLine - Wireframe - // * ePoint - Point cloud - _rasterization_state_info.polygonMode = polygon_mode; - _rasterization_state_info.lineWidth = 1.0; - - // Backface culling? - _rasterization_state_info.cullMode = vk::CullModeFlagBits::eBack; - _rasterization_state_info.frontFace = vk::FrontFace::eCounterClockwise; - - // Manipulate the depth values? - // TODO: Could be useful for shadow mapping - _rasterization_state_info.depthBiasEnable = false; - _rasterization_state_info.depthBiasConstantFactor = 0.0f; - _rasterization_state_info.depthBiasClamp = 0.0f; - _rasterization_state_info.depthBiasSlopeFactor = 0.0f; - } - - void Pipeline::create_multisampler_state() { - _multisampler_state_info.rasterizationSamples = - _device.get().get_physical().get_msaa_samples(); - _multisampler_state_info.sampleShadingEnable = true; - - // Multisampling rate for anti-aliasing the texture - _multisampler_state_info.minSampleShading = 0.5f; - } - - void Pipeline::create_blender_state() { - // TODO: Allow custom blend function? Add, subtract, multiply, etc. - _blender_attachment.blendEnable = true; - _blender_attachment.colorWriteMask = - vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | - vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA; - - // RGB blending operation - _blender_attachment.srcColorBlendFactor = vk::BlendFactor::eSrcAlpha; - _blender_attachment.dstColorBlendFactor = - vk::BlendFactor::eOneMinusSrcAlpha; - - // Alpha blending operation - _blender_attachment.srcAlphaBlendFactor = vk::BlendFactor::eOne; - _blender_attachment.dstAlphaBlendFactor = vk::BlendFactor::eZero; - _blender_attachment.alphaBlendOp = vk::BlendOp::eAdd; - - // Create the blender state - _blender_state_info.logicOpEnable = false; - _blender_state_info.logicOp = vk::LogicOp::eNoOp; - _blender_state_info.attachmentCount = 1; - _blender_state_info.pAttachments = &_blender_attachment; - } - - void Pipeline::create_depth_stencil_state() { - _depth_stencil_state_info.depthTestEnable = true; - _depth_stencil_state_info.depthWriteEnable = true; - _depth_stencil_state_info.depthCompareOp = vk::CompareOp::eLess; - _depth_stencil_state_info.depthBoundsTestEnable = false; - _depth_stencil_state_info.stencilTestEnable = false; - } - - void Pipeline::create_dynamic_state() { - _dynamic_state_info.dynamicStateCount = DYNAMIC_PIPELINE_STATES.size(); - _dynamic_state_info.pDynamicStates = DYNAMIC_PIPELINE_STATES.data(); - } - - const vk::Pipeline &Pipeline::get_handle() const { return _handle; } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Pipeline.hpp b/src/Graphics/Vulkan/Core/Pipeline.hpp deleted file mode 100644 index d3a7cc95..00000000 --- a/src/Graphics/Vulkan/Core/Pipeline.hpp +++ /dev/null @@ -1,152 +0,0 @@ -#pragma once - -#include -#include -#include - -#include - -#include "../../../Types.hpp" -#include "./Device.hpp" -#include "./PipelineLayout.hpp" -#include "./RenderPass.hpp" -#include "./ShaderModule.hpp" -#include "./VertexDescriptor.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Supported dynamic pipeline states. - * - */ - static constexpr std::array DYNAMIC_PIPELINE_STATES = { - vk::DynamicState::eViewport, // Size of the viewport - vk::DynamicState::eScissor, // Region of the viewport - vk::DynamicState::eBlendConstants // Blending function - }; - - /** - * @brief Wrapper class for a Vulkan rendering pipeline. - * - * In the typical case, there would be multiple pipelines for a - * variety of draw configuration modes. - * - * However, certain pipeline states can be dynamically set by - * commands during the draw calls (TODO: see VkDynamicState). - * - */ - class Pipeline { - vk::Pipeline _handle; - std::reference_wrapper _device; - - vk::PipelineVertexInputStateCreateInfo _vertex_input_state_info; - - vk::PipelineInputAssemblyStateCreateInfo _assembly_state_info; - - vk::Viewport _viewport; - vk::Rect2D _scissor; - vk::PipelineViewportStateCreateInfo _viewport_state_info; - - vk::PipelineRasterizationStateCreateInfo _rasterization_state_info; - - vk::PipelineMultisampleStateCreateInfo _multisampler_state_info; - - vk::PipelineColorBlendAttachmentState _blender_attachment; - vk::PipelineColorBlendStateCreateInfo _blender_state_info; - - vk::PipelineDepthStencilStateCreateInfo _depth_stencil_state_info; - - vk::PipelineDynamicStateCreateInfo _dynamic_state_info; - - /** - * @brief Create a pipeline shader stages. - * - * @param module Handle to vk::ShaderModule - * @param stage Shader stage - * @return vk::PipelineShaderStageCreateInfo - */ - vk::PipelineShaderStageCreateInfo - create_shader_stage(vk::ShaderModule module, - vk::ShaderStageFlagBits stage); - - /** - * @brief Create the vertex input state. - * - */ - void create_vertex_input_state(); - - /** - * @brief Create the input assembly state. - * - * @param primitive_topology - */ - void create_assembly_state(vk::PrimitiveTopology primitive_topology); - - /** - * @brief Create a viewport state object. - * - * @param extent - */ - void create_viewport_state(const vk::Extent2D &extent); - - /** - * @brief Create the rasterization state. - * - * @param polygon_mode - */ - void create_rasterization_state(vk::PolygonMode polygon_mode); - - /** - * @brief Create the multisampler state. - * - */ - void create_multisampler_state(); - - /** - * @brief Create the color blender state. - * - */ - void create_blender_state(); - - /** - * @brief Create the depth stencil state. - * - */ - void create_depth_stencil_state(); - - /** - * @brief Create the dynamic state. - * - */ - void create_dynamic_state(); - - public: - /** - * @brief Construct a new Pipeline object. - * - * @param device Reference to the logical device - * @param renderpass Reference to the render pass - * @param layout Pipeline layout - * @param primitive_topology Points, lines, or triangles - * @param polygon_mode Fill, wireframe, or point cloud - */ - Pipeline(Device &device, - RenderPass &renderpass, - Swapchain &swapchain, - PipelineLayout &layout, - vk::PrimitiveTopology primitive_topology, - vk::PolygonMode polygon_mode); - - /** - * @brief Destroy the Pipeline object. - * - */ - ~Pipeline(); - - /** - * @brief Get the handle to vk::Pipeline. - * - * @return const vk::Pipeline& - */ - const vk::Pipeline &get_handle() const; - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/PipelineLayout.cpp b/src/Graphics/Vulkan/Core/PipelineLayout.cpp deleted file mode 100644 index 8051a6b0..00000000 --- a/src/Graphics/Vulkan/Core/PipelineLayout.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "./PipelineLayout.hpp" - -namespace Dynamo::Graphics::Vulkan { - PipelineLayout::PipelineLayout(Device &device, ShaderList &shaders) : - _device(device), _shaders(shaders) { - // Extract reflection information from the shaders to construct - // descriptor layouts and push constant ranges - BindingGroups binding_groups; - for (std::reference_wrapper shader : _shaders) { - for (const vk::PushConstantRange &range : - shader.get().get_push_constant_ranges()) { - _push_constant_ranges.push_back(range); - } - for (const DescriptorBinding &data : - shader.get().get_descriptor_bindings()) { - LayoutBindings &bindings = binding_groups[data.set]; - - // Find duplicate binding in the set (i.e., from another shader - // stage) and merge their flags - b8 found = false; - for (vk::DescriptorSetLayoutBinding &rhs : bindings) { - if (rhs.binding == data.binding.binding) { - rhs.stageFlags |= data.binding.stageFlags; - found = true; - } - } - if (!found) { - bindings.push_back(data.binding); - } - } - } - - // Group bindings with similar set indexes into descriptor layouts - for (auto [set, bindings] : binding_groups) { - vk::DescriptorSetLayoutCreateInfo layout_info; - layout_info.bindingCount = bindings.size(); - layout_info.pBindings = bindings.data(); - - vk::DescriptorSetLayout layout = - _device.get().get_handle().createDescriptorSetLayout( - layout_info); - _descriptor_set_layouts.push_back(layout); - _descriptor_set_bindings.push_back(bindings); - } - - // Create the pipeline layout - vk::PipelineLayoutCreateInfo layout_info; - layout_info.setLayoutCount = _descriptor_set_layouts.size(); - layout_info.pSetLayouts = _descriptor_set_layouts.data(); - layout_info.pushConstantRangeCount = _push_constant_ranges.size(); - layout_info.pPushConstantRanges = _push_constant_ranges.data(); - - _handle = _device.get().get_handle().createPipelineLayout(layout_info); - } - - PipelineLayout::~PipelineLayout() { - // Destroy the pipeline layout - _device.get().get_handle().destroyPipelineLayout(_handle); - - // Destroy the descriptor set layouts - for (const vk::DescriptorSetLayout &layout : _descriptor_set_layouts) { - _device.get().get_handle().destroyDescriptorSetLayout(layout); - } - } - - const vk::PipelineLayout &PipelineLayout::get_handle() const { - return _handle; - } - - const ShaderList &PipelineLayout::get_shaders() const { return _shaders; } - - const std::vector & - PipelineLayout::get_descriptor_set_layouts() const { - return _descriptor_set_layouts; - } - - const std::vector & - PipelineLayout::get_descriptor_set_bindings() const { - return _descriptor_set_bindings; - } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/PipelineLayout.hpp b/src/Graphics/Vulkan/Core/PipelineLayout.hpp deleted file mode 100644 index dee1e693..00000000 --- a/src/Graphics/Vulkan/Core/PipelineLayout.hpp +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include - -#include "../../../Log/Log.hpp" -#include "../../../Types.hpp" -#include "./Device.hpp" -#include "./ShaderModule.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Auxillary datatypes to group descriptor bindings from each - * shader stage by set index. - * - */ - using LayoutBindings = std::vector; - using BindingGroups = std::map; - - /** - * @brief Wrapper class for a Vulkan pipeline layout. This describes what - * descriptor sets and push constants are used by the pipeline. - * - */ - class PipelineLayout { - vk::PipelineLayout _handle; - std::reference_wrapper _device; - - ShaderList _shaders; - - std::vector _push_constant_ranges; - std::vector _descriptor_set_bindings; - std::vector _descriptor_set_layouts; - - public: - /** - * @brief Construct a new PipelineLayout object. - * - * @param device Reference to the logical device - * @param shaders List of shader stage modules - */ - PipelineLayout(Device &device, ShaderList &shaders); - - /** - * @brief Destroy the PipelineLayout object. - * - */ - ~PipelineLayout(); - - /** - * @brief Get the handle object. - * - * @return const vk::PipelineLayout& - */ - const vk::PipelineLayout &get_handle() const; - - /** - * @brief Get the shader list. - * - * @return const ShaderList& - */ - const ShaderList &get_shaders() const; - - /** - * @brief Get the descriptor set layout list. - * - * @return const std::vector& - */ - const std::vector & - get_descriptor_set_layouts() const; - - /** - * @brief Get the descriptor set bindings list. - * - * @return const std::vector& - */ - const std::vector &get_descriptor_set_bindings() const; - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/RenderPass.cpp b/src/Graphics/Vulkan/Core/RenderPass.cpp deleted file mode 100644 index 2d9cbe8e..00000000 --- a/src/Graphics/Vulkan/Core/RenderPass.cpp +++ /dev/null @@ -1,151 +0,0 @@ -#include "./RenderPass.hpp" - -namespace Dynamo::Graphics::Vulkan { - RenderPass::RenderPass(Device &device, Swapchain &swapchain) : - _device(device), _swapchain(swapchain) { - - // Define attachment references to allow subpasses to reuse attachments - vk::AttachmentReference color_ref; - color_ref.attachment = 0; - color_ref.layout = vk::ImageLayout::eColorAttachmentOptimal; - - vk::AttachmentReference depth_ref; - depth_ref.attachment = 1; - depth_ref.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal; - - vk::AttachmentReference resolve_ref; - resolve_ref.attachment = 2; - resolve_ref.layout = vk::ImageLayout::eColorAttachmentOptimal; - - // Attachment set - std::array attachments; - attachments[color_ref.attachment] = create_color_attachment(); - attachments[depth_ref.attachment] = create_depth_attachment(); - attachments[resolve_ref.attachment] = create_resolve_attachment(); - - // Subpasses and their dependences - std::vector subpasses = - create_subpasses(color_ref, depth_ref, resolve_ref); - std::vector dependencies = - create_subpass_dependencies(); - - // Create the render pass - vk::RenderPassCreateInfo render_pass_info; - render_pass_info.attachmentCount = attachments.size(); - render_pass_info.pAttachments = attachments.data(); - render_pass_info.subpassCount = subpasses.size(); - render_pass_info.pSubpasses = subpasses.data(); - render_pass_info.dependencyCount = dependencies.size(); - render_pass_info.pDependencies = dependencies.data(); - - _handle = _device.get().get_handle().createRenderPass(render_pass_info); - } - - RenderPass::~RenderPass() { - _device.get().get_handle().destroyRenderPass(_handle); - } - - vk::AttachmentDescription RenderPass::create_color_attachment() { - const PhysicalDevice &physical = _device.get().get_physical(); - vk::AttachmentDescription attachment; - attachment.format = _swapchain.get().get_format().format; - attachment.samples = physical.get_msaa_samples(); - - // Clear data at the start of the render pass - attachment.loadOp = vk::AttachmentLoadOp::eClear; - attachment.storeOp = vk::AttachmentStoreOp::eDontCare; - - // Ignore the stencil component - attachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare; - attachment.stencilStoreOp = vk::AttachmentStoreOp::eDontCare; - - // The layout at the end should be optimal - attachment.initialLayout = vk::ImageLayout::eUndefined; - attachment.finalLayout = vk::ImageLayout::eColorAttachmentOptimal; - - return attachment; - } - - vk::AttachmentDescription RenderPass::create_depth_attachment() { - const PhysicalDevice &physical = _device.get().get_physical(); - vk::AttachmentDescription attachment; - attachment.format = physical.get_depth_format(); - attachment.samples = physical.get_msaa_samples(); - - // Clear data at the start of the render pass - attachment.loadOp = vk::AttachmentLoadOp::eClear; - attachment.storeOp = vk::AttachmentStoreOp::eDontCare; - - // Ignore stencil component - attachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare; - attachment.stencilStoreOp = vk::AttachmentStoreOp::eDontCare; - - // The layout at the end should be optimal - attachment.initialLayout = vk::ImageLayout::eUndefined; - attachment.finalLayout = - vk::ImageLayout::eDepthStencilAttachmentOptimal; - - return attachment; - } - - vk::AttachmentDescription RenderPass::create_resolve_attachment() { - vk::AttachmentDescription attachment; - attachment.format = _swapchain.get().get_format().format; - attachment.samples = vk::SampleCountFlagBits::e1; - - // Store the result in memory at the end of the render pass - attachment.loadOp = vk::AttachmentLoadOp::eDontCare; - attachment.storeOp = vk::AttachmentStoreOp::eStore; - - // Ignore stencil component - attachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare; - attachment.stencilStoreOp = vk::AttachmentStoreOp::eDontCare; - - // The layout at the end should be presentable to the screen - attachment.initialLayout = vk::ImageLayout::eUndefined; - attachment.finalLayout = vk::ImageLayout::ePresentSrcKHR; - - return attachment; - } - - std::vector - RenderPass::create_subpasses(vk::AttachmentReference &color_ref, - vk::AttachmentReference &depth_ref, - vk::AttachmentReference &resolve_ref) { - vk::SubpassDescription initial_subpass; - initial_subpass.pipelineBindPoint = vk::PipelineBindPoint::eGraphics; - initial_subpass.colorAttachmentCount = 1; - initial_subpass.pColorAttachments = &color_ref; - initial_subpass.pDepthStencilAttachment = &depth_ref; - initial_subpass.pResolveAttachments = &resolve_ref; - return {initial_subpass}; - } - - std::vector - RenderPass::create_subpass_dependencies() { - vk::SubpassDependency subpass_dependency; - - // Current subpass -> Next subpass - subpass_dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - subpass_dependency.dstSubpass = 0; - - // Pipeline stage dependences - subpass_dependency.srcStageMask = - vk::PipelineStageFlagBits::eColorAttachmentOutput | - vk::PipelineStageFlagBits::eEarlyFragmentTests; - subpass_dependency.dstStageMask = - vk::PipelineStageFlagBits::eColorAttachmentOutput | - vk::PipelineStageFlagBits::eEarlyFragmentTests; - - // Access flags - subpass_dependency.srcAccessMask = vk::AccessFlagBits::eNoneKHR; - subpass_dependency.dstAccessMask = - vk::AccessFlagBits::eColorAttachmentWrite | - vk::AccessFlagBits::eDepthStencilAttachmentWrite; - - // Only one dependency because we only have one subpass - return {subpass_dependency}; - } - - const vk::RenderPass &RenderPass::get_handle() const { return _handle; } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/RenderPass.hpp b/src/Graphics/Vulkan/Core/RenderPass.hpp deleted file mode 100644 index f0da3306..00000000 --- a/src/Graphics/Vulkan/Core/RenderPass.hpp +++ /dev/null @@ -1,91 +0,0 @@ -#pragma once - -#include - -#include "./Device.hpp" -#include "./Image.hpp" -#include "./Swapchain.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Wrapper class for a Vulkan render pass that defines the - * relationships between different attachments (color, depth, and stencil - * buffers), how these attachments are loaded and stored, and their - * dependencies. - * - * TODO: Does it make sense for this to be a class? RenderPass is a very - * static object with a default state. It might be better to write - * create_*_renderpass() functions instead if we plan to make custom - * passes / subpasses. - * - */ - class RenderPass { - vk::RenderPass _handle; - std::reference_wrapper _device; - std::reference_wrapper _swapchain; - - /** - * @brief Create a color attachment - * - * @return vk::AttachmentDescription - */ - vk::AttachmentDescription create_color_attachment(); - - /** - * @brief Create a depth attachment - * - * @return vk::AttachmentDescription - */ - vk::AttachmentDescription create_depth_attachment(); - - /** - * @brief Create a resolve attachment for the multisampling pass - * - * @return vk::AttachmentDescription - */ - vk::AttachmentDescription create_resolve_attachment(); - - /** - * @brief Create the list of all subpasses - * - * @param color_ref Color attachment reference - * @param depth_ref Depth attachment reference - * @param resolve_ref Resolve attachment reference - * @return std::vector - */ - std::vector - create_subpasses(vk::AttachmentReference &color_ref, - vk::AttachmentReference &depth_ref, - vk::AttachmentReference &resolve_ref); - - /** - * @brief Create a subpass dependencies, which defines the connectivity - * of the subpass graph - * - * @return std::vector - */ - std::vector create_subpass_dependencies(); - - public: - /** - * @brief Construct a new RenderPass object - * - * @param device Reference to the logical device - * @param swapchain Reference to the swapchain - */ - RenderPass(Device &device, Swapchain &swapchain); - - /** - * @brief Destroy the RenderPass object - * - */ - ~RenderPass(); - - /** - * @brief Get the handle to vk::RenderPass - * - * @return const vk::RenderPass& - */ - const vk::RenderPass &get_handle() const; - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Sampler.cpp b/src/Graphics/Vulkan/Core/Sampler.cpp deleted file mode 100644 index 86eeadef..00000000 --- a/src/Graphics/Vulkan/Core/Sampler.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "./Sampler.hpp" - -namespace Dynamo::Graphics::Vulkan { - Sampler::Sampler(Device &device, u32 max_lod) : _device(device) { - vk::SamplerCreateInfo sampler_info; - sampler_info.magFilter = vk::Filter::eLinear; - sampler_info.minFilter = vk::Filter::eLinear; - sampler_info.mipmapMode = vk::SamplerMipmapMode::eLinear; - - sampler_info.addressModeU = vk::SamplerAddressMode::eRepeat; - sampler_info.addressModeV = vk::SamplerAddressMode::eRepeat; - sampler_info.addressModeW = vk::SamplerAddressMode::eRepeat; - - sampler_info.mipLodBias = 0.0f; - - sampler_info.anisotropyEnable = true; - sampler_info.maxAnisotropy = - _device.get().get_physical().get_limits().maxSamplerAnisotropy; - - sampler_info.compareEnable = false; - sampler_info.compareOp = vk::CompareOp::eAlways; - - sampler_info.minLod = 0.0f; - sampler_info.maxLod = max_lod; - - sampler_info.borderColor = vk::BorderColor::eIntOpaqueBlack; - sampler_info.unnormalizedCoordinates = false; - - _handle = _device.get().get_handle().createSampler(sampler_info); - } - - Sampler::~Sampler() { _device.get().get_handle().destroySampler(_handle); } - - const vk::Sampler &Sampler::get_handle() const { return _handle; } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Sampler.hpp b/src/Graphics/Vulkan/Core/Sampler.hpp deleted file mode 100644 index 2113dd69..00000000 --- a/src/Graphics/Vulkan/Core/Sampler.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include - -#include - -#include "../../../Types.hpp" -#include "./Device.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Wrapper class for a Vulkan image sampler. This pre-processes - * images before they are accessed by the shader stages (e.g. bilinear - * filtering, anisotropic filtering). - * - */ - class Sampler { - vk::Sampler _handle; - std::reference_wrapper _device; - - public: - /** - * @brief Construct a new Sampler object - * - * @param device Reference to the logical device - * @param max_lod Maximum level of detail - */ - Sampler(Device &device, u32 max_lod); - - /** - * @brief Destroy the Sampler object - * - */ - ~Sampler(); - - /** - * @brief Get the handle to vk::Sampler - * - * @return const vk::Sampler& - */ - const vk::Sampler &get_handle() const; - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Semaphore.cpp b/src/Graphics/Vulkan/Core/Semaphore.cpp deleted file mode 100644 index c082dd4c..00000000 --- a/src/Graphics/Vulkan/Core/Semaphore.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "./Semaphore.hpp" - -namespace Dynamo::Graphics::Vulkan { - Semaphore::Semaphore(Device &device) : _device(device) { - vk::SemaphoreCreateInfo semaphore_info; - _handle = _device.get().get_handle().createSemaphore(semaphore_info); - } - - Semaphore::~Semaphore() { - _device.get().get_handle().destroySemaphore(_handle); - } - - const vk::Semaphore &Semaphore::get_handle() const { return _handle; } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Semaphore.hpp b/src/Graphics/Vulkan/Core/Semaphore.hpp deleted file mode 100644 index 33e3a769..00000000 --- a/src/Graphics/Vulkan/Core/Semaphore.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include - -#include "./Device.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Wrapper class of a Vulkan semaphore for queue synchronization. - * - * Vulkan does not guarantee that commands submitted one after another on - * different queues will finish in that order, since those commands can - * run in parallel. - * - * A semaphore is used to ensure that the commands in one queue waits for - * the commands in another queue to finish. - * - */ - class Semaphore { - vk::Semaphore _handle; - std::reference_wrapper _device; - - public: - /** - * @brief Construct a new Semaphore object - * - * @param device - */ - Semaphore(Device &device); - - /** - * @brief Destroy the Semaphore object - * - */ - ~Semaphore(); - - /** - * @brief Get the handle to vk::Semaphore - * - * @return const vk::Semaphore& - */ - const vk::Semaphore &get_handle() const; - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/ShaderModule.cpp b/src/Graphics/Vulkan/Core/ShaderModule.cpp deleted file mode 100644 index 32bd0467..00000000 --- a/src/Graphics/Vulkan/Core/ShaderModule.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include "./ShaderModule.hpp" - -namespace Dynamo::Graphics::Vulkan { - ShaderModule::ShaderModule(Device &device, - const std::string filename, - vk::ShaderStageFlagBits stage) : - _device(device), - _filename(filename), _stage(stage) { - std::ifstream file(filename, std::ios::ate | std::ios::binary); - if (!file.is_open()) { - Log::error("Unable to load shader source file: {}", filename); - } - - _bytecode.resize(file.tellg()); - file.seekg(0); - file.read(_bytecode.data(), _bytecode.size()); - file.close(); - - SpvReflectShaderModule module; - SpvReflectResult result = spvReflectCreateShaderModule(_bytecode.size(), - _bytecode.data(), - &module); - DYN_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); - - parse_push_constants(module); - parse_descriptor_layouts(module); - } - - void - ShaderModule::parse_descriptor_layouts(SpvReflectShaderModule &module) { - u32 count = 0; - SpvReflectDescriptorSet *spv_sets; - spvReflectEnumerateDescriptorSets(&module, &count, nullptr); - spvReflectEnumerateDescriptorSets(&module, &count, &spv_sets); - - for (u32 i = 0; i < count; i++) { - SpvReflectDescriptorSet &spv_set = spv_sets[i]; - - // Enumerate each binding - for (u32 j = 0; j < spv_set.binding_count; j++) { - SpvReflectDescriptorBinding &spv_binding = *spv_set.bindings[j]; - - DescriptorBinding binding; - binding.set = spv_binding.set; - binding.binding.binding = spv_binding.binding; - binding.binding.descriptorType = - static_cast( - spv_binding.descriptor_type); - binding.binding.stageFlags = _stage; - - // Compute the descriptor count - binding.binding.descriptorCount = 1; - for (u32 k = 0; k < spv_binding.array.dims_count; k++) { - u32 dim = spv_binding.array.dims[k]; - binding.binding.descriptorCount *= dim; - } - _descriptor_bindings.push_back(binding); - } - } - -#ifdef DYN_DEBUG - Log::info("`{}` descriptor bindings", _filename); - for (const DescriptorBinding &binding : _descriptor_bindings) { - Log::info("* (set = {}, binding = {}) {}[{}]", - binding.set, - binding.binding.binding, - vk::to_string(binding.binding.descriptorType), - binding.binding.descriptorCount); - } - Log::info(""); -#endif - } - - void ShaderModule::parse_push_constants(SpvReflectShaderModule &module) { - u32 count = 0; - SpvReflectBlockVariable *blocks; - spvReflectEnumeratePushConstantBlocks(&module, &count, nullptr); - spvReflectEnumeratePushConstantBlocks(&module, &count, &blocks); - - for (u32 i = 0; i < count; i++) { - SpvReflectBlockVariable &block = blocks[i]; - vk::PushConstantRange range; - range.stageFlags = _stage; - range.offset = block.offset; - range.size = block.size; - _push_constant_ranges.push_back(range); - -#ifdef DYN_DEBUG - Log::info("`{}` push constant: {} ({} b, offset = {})", - _filename, - block.name, - block.size, - block.offset); - for (u32 j = 0; j < block.member_count; j++) { - SpvReflectBlockVariable &member = block.members[j]; - Log::info("* {} ({} b)", member.name, member.size); - } - Log::info(""); -#endif - } - } - - vk::UniqueShaderModule ShaderModule::get_handle() { - // Create the shader module from the file - vk::ShaderModuleCreateInfo shader_info; - shader_info.codeSize = _bytecode.size(); - shader_info.pCode = reinterpret_cast(_bytecode.data()); - - return _device.get().get_handle().createShaderModuleUnique(shader_info); - } - - vk::ShaderStageFlagBits ShaderModule::get_stage() const { return _stage; } - - const std::vector &ShaderModule::get_bytecode() { return _bytecode; } - - const std::string &ShaderModule::get_filename() const { return _filename; } - - const std::vector & - ShaderModule::get_push_constant_ranges() const { - return _push_constant_ranges; - } - - const std::vector & - ShaderModule::get_descriptor_bindings() const { - return _descriptor_bindings; - } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/ShaderModule.hpp b/src/Graphics/Vulkan/Core/ShaderModule.hpp deleted file mode 100644 index abfa38f5..00000000 --- a/src/Graphics/Vulkan/Core/ShaderModule.hpp +++ /dev/null @@ -1,115 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include - -#include "../../../Log/Log.hpp" -#include "../../../Types.hpp" -#include "./Device.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Descriptor set binding information. - * - */ - struct DescriptorBinding { - u32 set; - vk::DescriptorSetLayoutBinding binding; - }; - - /** - * @brief Wrapper class for a Vulkan shader module which can be plugged into - * a Vulkan pipeline. - * - */ - class ShaderModule { - std::vector _bytecode; - std::reference_wrapper _device; - - std::string _filename; - vk::ShaderStageFlagBits _stage; - - std::vector _descriptor_bindings; - std::vector _push_constant_ranges; - - /** - * @brief Parse the descriptor set layouts. - * - */ - void parse_descriptor_layouts(SpvReflectShaderModule &module); - - /** - * @brief Parse the push constants from the bytecode. - * - */ - void parse_push_constants(SpvReflectShaderModule &module); - - public: - /** - * @brief Construct a new ShaderModule object. - * - * @param device Reference to the logical device - * @param filename Path to the shader source file - * @param stage Stage of the pipeline it represents - */ - ShaderModule(Device &device, - const std::string filename, - vk::ShaderStageFlagBits stage); - - /** - * @brief Get the handle to vk::UniqueShaderModule. - * - * This is a temporary object that should be destroyed as soon as - * pipeline creation ceases. - * - * @return const vk::UniqueShaderModule& - */ - vk::UniqueShaderModule get_handle(); - - /** - * @brief Get the stage of the pipeline the shader represents. - * - * @return const vk::ShaderStageFlagBits - */ - vk::ShaderStageFlagBits get_stage() const; - - /** - * @brief Get the bytecode of the shader program. - * - * @return const std::vector& - */ - const std::vector &get_bytecode(); - - /** - * @brief Get the filename of the shader module. - * - * @return const std::string& - */ - const std::string &get_filename() const; - - /** - * @brief Get the push constant ranges. - * - * @return const std::vector& - */ - const std::vector & - get_push_constant_ranges() const; - - /** - * @brief Get the descriptor bindings accessed from this shader. - * - * @return const std::vector& - */ - const std::vector &get_descriptor_bindings() const; - }; - - /** - * @brief List of shader stage modules. - * - */ - using ShaderList = std::vector>; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Swapchain.cpp b/src/Graphics/Vulkan/Core/Swapchain.cpp deleted file mode 100644 index 4bce923d..00000000 --- a/src/Graphics/Vulkan/Core/Swapchain.cpp +++ /dev/null @@ -1,165 +0,0 @@ -#include "./Swapchain.hpp" - -namespace Dynamo::Graphics::Vulkan { - Swapchain::Swapchain(Device &device, - Display &display, - vk::SurfaceKHR surface) : - _device(device) { - PhysicalDevice &physical = device.get_physical(); - const SwapchainOptions &options = physical.get_swapchain_options(); - calculate_extent(options.capabilities, display); - select_format(options.formats); - set_presentation_mode(options.present_modes, display); - - // Determines the number of images to be rendered to - // This allows multiple buffering - u32 image_count = options.capabilities.minImageCount + 1; - if (options.capabilities.maxImageCount) { - image_count = - std::min(image_count, options.capabilities.maxImageCount); - } - - // Define the swapchain - vk::SwapchainCreateInfoKHR swapchain_info; - swapchain_info.surface = surface; - swapchain_info.minImageCount = image_count; - swapchain_info.preTransform = options.capabilities.currentTransform; - swapchain_info.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque; - swapchain_info.presentMode = _present_mode; - swapchain_info.clipped = true; - - // Define shared properties for each swapchain image - swapchain_info.imageFormat = _format.format; - swapchain_info.imageColorSpace = _format.colorSpace; - swapchain_info.imageExtent = _extent; - swapchain_info.imageArrayLayers = 1; - swapchain_info.imageUsage = vk::ImageUsageFlagBits::eColorAttachment; - swapchain_info.imageSharingMode = vk::SharingMode::eExclusive; - - // Allow multiple command queues to access the images concurrently - const QueueProperties &graphics_queue_properties = - physical.get_queue_properties(QueueFamily::Graphics); - const QueueProperties &transfer_queue_properties = - physical.get_queue_properties(QueueFamily::Transfer); - const QueueProperties &present_queue_properties = - physical.get_queue_properties(QueueFamily::Present); - - std::array index_arr; - index_arr[0] = present_queue_properties.family_id; - u32 index_count = 1; - if (graphics_queue_properties.family_id != - present_queue_properties.family_id) { - index_arr[index_count++] = graphics_queue_properties.family_id; - } - if (transfer_queue_properties.family_id != - present_queue_properties.family_id) { - index_arr[index_count++] = transfer_queue_properties.family_id; - } - if (index_count > 1) { - swapchain_info.imageSharingMode = vk::SharingMode::eConcurrent; - swapchain_info.queueFamilyIndexCount = index_count; - swapchain_info.pQueueFamilyIndices = index_arr.data(); - } - - // Create the swapchain and its images - const vk::Device &logical = device.get_handle(); - _handle = logical.createSwapchainKHR(swapchain_info); - for (vk::Image &vkimg : logical.getSwapchainImagesKHR(_handle)) { - std::unique_ptr image = - std::make_unique(device, vkimg, _format.format); - std::unique_ptr view = - std::make_unique(*image, - vk::ImageViewType::e2D, - vk::ImageAspectFlagBits::eColor, - 1); - _images.emplace_back(std::move(image)); - _views.emplace_back(std::move(view)); - } - } - - Swapchain::~Swapchain() { - _device.get().get_handle().destroySwapchainKHR(_handle); - } - - void - Swapchain::calculate_extent(const vk::SurfaceCapabilitiesKHR &capabilities, - Display &display) { - Vec2 size = display.get_framebuffer_size(); - _extent.width = std::clamp(static_cast(size.x), - capabilities.minImageExtent.width, - capabilities.maxImageExtent.width); - _extent.height = std::clamp(static_cast(size.y), - capabilities.minImageExtent.height, - capabilities.maxImageExtent.height); - } - - void - Swapchain::select_format(const std::vector &formats) { - _format = formats[0]; - for (const vk::SurfaceFormatKHR &format : formats) { - if (format.format == vk::Format::eB8G8R8A8Srgb && - format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { - _format = format; - return; - } - } - } - - void Swapchain::set_presentation_mode( - const std::vector &present_modes, - Display &display) { - _present_mode = vk::PresentModeKHR::eFifo; - for (const vk::PresentModeKHR &mode : present_modes) { - if (!display.is_vsync() && mode == vk::PresentModeKHR::eImmediate) { - _present_mode = mode; - } else if (mode == vk::PresentModeKHR::eMailbox) { - _present_mode = mode; - } - } - } - - const vk::SwapchainKHR &Swapchain::get_handle() const { return _handle; } - - const std::vector> & - Swapchain::get_images() const { - return _images; - } - - const std::vector> & - Swapchain::get_views() const { - return _views; - } - - const vk::Extent2D &Swapchain::get_extent() const { return _extent; } - - const vk::SurfaceFormatKHR &Swapchain::get_format() const { - return _format; - } - - const vk::PresentModeKHR &Swapchain::get_present_mode() const { - return _present_mode; - } - - std::optional - Swapchain::get_presentation_image(const Semaphore &semaphore) const { - vk::ResultValue acquired = - _device.get().get_handle().acquireNextImageKHR( - _handle, - UINT64_MAX, - semaphore.get_handle(), - nullptr); - - switch (acquired.result) { - case vk::Result::eSuccess: - return acquired.value; - case vk::Result::eSuboptimalKHR: - case vk::Result::eErrorOutOfDateKHR: - return {}; - default: - Log::error("Could not acquire image from the Vulkan swapchain: {}", - vk::to_string(acquired.result)); - break; - } - return acquired.value; - } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Swapchain.hpp b/src/Graphics/Vulkan/Core/Swapchain.hpp deleted file mode 100644 index 0206c8bf..00000000 --- a/src/Graphics/Vulkan/Core/Swapchain.hpp +++ /dev/null @@ -1,127 +0,0 @@ -#pragma once - -#include -#include - -#include - -#include "../../../Core/Display.hpp" -#include "../../../Log/Log.hpp" -#include "../../../Types.hpp" -#include "./Device.hpp" -#include "./Image.hpp" -#include "./ImageView.hpp" -#include "./Semaphore.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Wrapper class for a Vulkan swapchain. This holds the list of - * images (and their views) that are actually presented on the Display. - * - */ - class Swapchain { - vk::SwapchainKHR _handle; - std::reference_wrapper _device; - - std::vector> _images; - std::vector> _views; - - vk::Extent2D _extent; - vk::SurfaceFormatKHR _format; - vk::PresentModeKHR _present_mode; - - /** - * @brief Calculate the extent of the swapchain. - * - * @param capabilities - * @param display - */ - void calculate_extent(const vk::SurfaceCapabilitiesKHR &capabilities, - Display &display); - - /** - * @brief Select the surface format. - * - * @param formats - */ - void select_format(const std::vector &formats); - - /** - * @brief Set the presentation mode of the swapchain. - * - * @param present_modes - * @param display - */ - void set_presentation_mode( - const std::vector &present_modes, - Display &display); - - public: - /** - * @brief Construct a new Swapchain object. - * - * @param device Reference to the logical device - * @param display Reference to the display window - * @param surface Vulkan surface handle - */ - Swapchain(Device &device, Display &display, vk::SurfaceKHR surface); - - /** - * @brief Destroy the Swapchain object. - * - */ - ~Swapchain(); - - /** - * @brief Get the handle to the vk::SwapchainKHR. - * - * @return const vk::SwapchainKHR& - */ - const vk::SwapchainKHR &get_handle() const; - - /** - * @brief Get the array of presentable images. - * - * @return const std::vector>& - */ - const std::vector> &get_images() const; - - /** - * @brief Get the array of image views, which map one-to-one with the - * presentable images array. - * - * @return const std::vector>& - */ - const std::vector> &get_views() const; - - /** - * @brief Get the extent of the swapchain. - * - * @return const vk::Extent2D& - */ - const vk::Extent2D &get_extent() const; - - /** - * @brief Get the surface format of the swapchain. - * - * @return const vk::SurfaceFormatKHR& - */ - const vk::SurfaceFormatKHR &get_format() const; - - /** - * @brief Get the present mode of the swapchain. - * - * @return const vk::PresentModeKHR& - */ - const vk::PresentModeKHR &get_present_mode() const; - - /** - * @brief Acquire the index to the next presentation target image. - * - * @param semaphore Semaphore to signal - * @return std::optional - */ - std::optional - get_presentation_image(const Semaphore &semaphore) const; - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Texture.cpp b/src/Graphics/Vulkan/Core/Texture.cpp deleted file mode 100644 index e4425bc3..00000000 --- a/src/Graphics/Vulkan/Core/Texture.cpp +++ /dev/null @@ -1,273 +0,0 @@ -#include "./Texture.hpp" - -namespace Dynamo::Graphics::Vulkan { - Texture::Texture(u8 pixels[], - u32 width, - u32 height, - Device &device, - MemoryPool &memory_pool, - Buffer &staging_buffer, - CommandPool &command_pool, - vk::Queue graphics_queue) : - _width(width), - _height(height), - _mip_levels(std::floor(std::log2(std::max(width, height))) + 1), - _image(device, - memory_pool, - width, - height, - 1, - _mip_levels, - 1, - vk::Format::eR8G8B8A8Srgb, - vk::ImageType::e2D, - vk::ImageTiling::eOptimal, - TEXTURE_IMAGE_USAGE_FLAGS, - vk::SampleCountFlagBits::e1), - _view(_image, - vk::ImageViewType::e2D, - vk::ImageAspectFlagBits::eColor, - 1), - _device(device), _command_pool(command_pool) { - _command_buffer = std::move( - command_pool.allocate(vk::CommandBufferLevel::ePrimary, 1)[0]); - _graphics_queue = graphics_queue; - - transition_layout(vk::ImageLayout::eUndefined, - vk::ImageLayout::eTransferDstOptimal); - copy_pixels(pixels, staging_buffer); - generate_mipmaps(); - } - - void Texture::transition_layout(vk::ImageLayout src, vk::ImageLayout dst) { - // Define the memory barrier - vk::ImageMemoryBarrier barrier; - barrier.srcAccessMask = vk::AccessFlagBits::eNoneKHR; - barrier.dstAccessMask = vk::AccessFlagBits::eNoneKHR; - barrier.oldLayout = src; - barrier.newLayout = dst; - barrier.srcQueueFamilyIndex = 0; - barrier.dstQueueFamilyIndex = 0; - barrier.image = _image.get_handle(); - - barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = _mip_levels; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - - vk::PipelineStageFlags src_stage, dst_stage; - if (src == vk::ImageLayout::eUndefined && - dst == vk::ImageLayout::eTransferDstOptimal) { - barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite; - src_stage = vk::PipelineStageFlagBits::eTopOfPipe; - dst_stage = vk::PipelineStageFlagBits::eTransfer; - } else if (src == vk::ImageLayout::eTransferDstOptimal && - dst == vk::ImageLayout::eShaderReadOnlyOptimal) { - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; - src_stage = vk::PipelineStageFlagBits::eTransfer; - dst_stage = vk::PipelineStageFlagBits::eFragmentShader; - } else { - Log::error("Texture loading failed, Vulkan layout transition from " - "{} to {} is unsupported.", - vk::to_string(src), - vk::to_string(dst)); - } - - // Reset command buffers - _command_pool.get().reset( - vk::CommandPoolResetFlagBits::eReleaseResources); - - // Execute the transition command - vk::CommandBufferBeginInfo begin_info; - begin_info.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit; - - _command_buffer->begin(begin_info); - _command_buffer->pipelineBarrier( - src_stage, - dst_stage, - vk::DependencyFlagBits::eByRegion, // TODO - nullptr, - nullptr, - barrier); - _command_buffer->end(); - - // Submit the command to the graphics queue - vk::SubmitInfo submit_info; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &_command_buffer.get(); - - _graphics_queue.submit(submit_info, nullptr); - _graphics_queue.waitIdle(); - } - - void Texture::copy_pixels(u8 pixels[], Buffer &staging_buffer) { - // Copy the pixel data to the staging buffer - u32 image_size = _width * _height * 4; - u32 offset = staging_buffer.reserve(image_size, 1); - staging_buffer.write(reinterpret_cast(pixels), - offset, - image_size); - staging_buffer.free(offset); - - // Copy from the staging buffer to the image - vk::BufferImageCopy copy_region; - copy_region.imageSubresource.aspectMask = - vk::ImageAspectFlagBits::eColor; - copy_region.imageSubresource.mipLevel = 0; - copy_region.imageSubresource.baseArrayLayer = 0; - copy_region.imageSubresource.layerCount = 1; - - copy_region.imageExtent.width = _width; - copy_region.imageExtent.height = _height; - copy_region.imageExtent.depth = 1; - - // Reset command buffers - _command_pool.get().reset( - vk::CommandPoolResetFlagBits::eReleaseResources); - - vk::CommandBufferBeginInfo begin_info; - begin_info.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit; - - _command_buffer->begin(begin_info); - _command_buffer->copyBufferToImage(staging_buffer.get_handle(), - _image.get_handle(), - vk::ImageLayout::eTransferDstOptimal, - 1, - ©_region); - _command_buffer->end(); - - // Submit to the queue - vk::SubmitInfo submit_info; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &_command_buffer.get(); - - _graphics_queue.submit(submit_info, nullptr); - _graphics_queue.waitIdle(); - } - - void Texture::generate_mipmaps() { - auto format_properties = - _device.get().get_physical().get_format_properties( - vk::Format::eR8G8B8A8Srgb); - auto tiling_features = format_properties.optimalTilingFeatures; - if (!(tiling_features & - vk::FormatFeatureFlagBits::eSampledImageFilterLinear)) { - // Cannot perform linear filtering to generate mipmaps - // Just transition straight to shader readable layout - transition_layout(vk::ImageLayout::eTransferDstOptimal, - vk::ImageLayout::eShaderReadOnlyOptimal); - return; - } - - vk::ImageMemoryBarrier barrier; - barrier.srcQueueFamilyIndex = 0; - barrier.dstQueueFamilyIndex = 0; - barrier.image = _image.get_handle(); - - barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = 1; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - - // Reset command buffers - _command_pool.get().reset( - vk::CommandPoolResetFlagBits::eReleaseResources); - - // Execute commands for blitting the mipped textures - vk::CommandBufferBeginInfo begin_info; - begin_info.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit; - _command_buffer->begin(begin_info); - - u32 mip_width = _width; - u32 mip_height = _height; - for (u32 i = 1; i < _mip_levels; i++) { - barrier.subresourceRange.baseMipLevel = i - 1; - barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal; - barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal; - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead; - - _command_buffer->pipelineBarrier( - vk::PipelineStageFlagBits::eTransfer, - vk::PipelineStageFlagBits::eTransfer, - vk::DependencyFlagBits::eByRegion, - nullptr, - nullptr, - barrier); - - // Blit the new mip - vk::ImageBlit blit; - blit.srcOffsets[0] = vk::Offset3D(0, 0, 0); - blit.srcOffsets[1] = vk::Offset3D(mip_width, mip_height, 1); - blit.srcSubresource.aspectMask = vk::ImageAspectFlagBits::eColor; - blit.srcSubresource.mipLevel = i - 1; - blit.srcSubresource.baseArrayLayer = 0; - blit.srcSubresource.layerCount = 1; - - blit.dstOffsets[0] = vk::Offset3D(0, 0, 0); - blit.dstOffsets[1] = - vk::Offset3D(mip_width > 1 ? mip_width / 2 : 1, - mip_height > 1 ? mip_height / 2 : 1, - 1); - blit.dstSubresource.aspectMask = vk::ImageAspectFlagBits::eColor; - blit.dstSubresource.mipLevel = i; - blit.dstSubresource.baseArrayLayer = 0; - blit.dstSubresource.layerCount = 1; - - _command_buffer->blitImage(_image.get_handle(), - vk::ImageLayout::eTransferSrcOptimal, - _image.get_handle(), - vk::ImageLayout::eTransferDstOptimal, - blit, - vk::Filter::eLinear); - - // Transition mip to shader readable format - barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal; - barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal; - barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; - - _command_buffer->pipelineBarrier( - vk::PipelineStageFlagBits::eTransfer, - vk::PipelineStageFlagBits::eFragmentShader, - vk::DependencyFlagBits::eByRegion, - nullptr, - nullptr, - barrier); - - if (mip_width > 1) mip_width /= 2; - if (mip_height > 1) mip_height /= 2; - } - - // Transition last mip to optimal shader readable layout - barrier.subresourceRange.baseMipLevel = _mip_levels - 1; - barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal; - barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal; - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; - - _command_buffer->pipelineBarrier( - vk::PipelineStageFlagBits::eTransfer, - vk::PipelineStageFlagBits::eFragmentShader, - vk::DependencyFlagBits::eByRegion, - nullptr, - nullptr, - barrier); - _command_buffer->end(); - - // Submit to the queue - vk::SubmitInfo submit_info; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &_command_buffer.get(); - - _graphics_queue.submit(submit_info, nullptr); - _graphics_queue.waitIdle(); - } - - const Image &Texture::get_image() const { return _image; } - - const ImageView &Texture::get_view() const { return _view; } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/Texture.hpp b/src/Graphics/Vulkan/Core/Texture.hpp deleted file mode 100644 index c6e13ff9..00000000 --- a/src/Graphics/Vulkan/Core/Texture.hpp +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -#include - -#include "../../../Types.hpp" -#include "./Buffer.hpp" -#include "./CommandPool.hpp" -#include "./Device.hpp" -#include "./Image.hpp" -#include "./ImageView.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Texture image usage flags. - * - */ - constexpr vk::ImageUsageFlags TEXTURE_IMAGE_USAGE_FLAGS = - vk::ImageUsageFlagBits::eTransferSrc | - vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled; - - /** - * @brief 2D Texture. - * - */ - class Texture { - u32 _width; - u32 _height; - u32 _mip_levels; - - UserImage _image; - ImageView _view; - - std::reference_wrapper _device; - std::reference_wrapper _command_pool; - - vk::UniqueCommandBuffer _command_buffer; - vk::Queue _graphics_queue; - - /** - * @brief Transition the texture image to a new layout. - * - * @param src - * @param dst - */ - void transition_layout(vk::ImageLayout src, vk::ImageLayout dst); - - /** - * @brief Copy pixels to the image via a staging buffer. - * - * @param pixels - * @param staging_buffer - */ - void copy_pixels(u8 pixels[], Buffer &staging_buffer); - - /** - * @brief Generate the image mip maps. - * - */ - void generate_mipmaps(); - - public: - Texture(u8 pixels[], - u32 width, - u32 height, - Device &device, - MemoryPool &memory_pool, - Buffer &staging_buffer, - CommandPool &command_pool, - vk::Queue graphics_queue); - - /** - * @brief Get the image. - * - * @return const Image& - */ - const Image &get_image() const; - - /** - * @brief Get the image view. - * - * @return const ImageView& - */ - const ImageView &get_view() const; - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Core/VertexDescriptor.hpp b/src/Graphics/Vulkan/Core/VertexDescriptor.hpp deleted file mode 100644 index c3413cad..00000000 --- a/src/Graphics/Vulkan/Core/VertexDescriptor.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include - -#include - -#include "../../Vertex.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Binding description of a Vertex. - * - */ - static constexpr vk::VertexInputBindingDescription - VERTEX_BINDING_DESCRIPTION = vk::VertexInputBindingDescription( - 0, // Index in array of bindings - sizeof(Vertex) // Stride (memory buffer traversal) - ); - - /** - * @brief Attribute descriptions of a Vertex. - * - */ - static constexpr std::array - VERTEX_ATTRIBUTE_DESCRIPTIONS = { - vk::VertexInputAttributeDescription(0, - 0, - vk::Format::eR32G32B32Sfloat, - offsetof(Vertex, position)), - vk::VertexInputAttributeDescription(1, - 0, - vk::Format::eR32G32B32Sfloat, - offsetof(Vertex, normal)), - vk::VertexInputAttributeDescription(2, - 0, - vk::Format::eR32G32Sfloat, - offsetof(Vertex, texture)), - }; -} // namespace Dynamo::Graphics::Vulkan diff --git a/src/Graphics/Vulkan/Renderer.cpp b/src/Graphics/Vulkan/Renderer.cpp deleted file mode 100644 index e8e51b31..00000000 --- a/src/Graphics/Vulkan/Renderer.cpp +++ /dev/null @@ -1,466 +0,0 @@ -#include "Renderer.hpp" - -namespace Dynamo::Graphics::Vulkan { - Renderer::Renderer(Display &display) : _display(display) { - enumerate_extensions(); - create_instance(); - create_surface(); - - create_device(); - create_pools(); - - create_swapchain(); - create_synchronizers(); - - create_depth_buffer(); - create_color_buffer(); - - create_framebuffers(); - create_pipeline(); - create_command_buffers(); - - create_buffers(); - - clear(Color(0, 0, 0)); - _depth_clear.depthStencil.depth = 1; - _depth_clear.depthStencil.stencil = 0; - } - - Renderer::~Renderer() { - // Wait for all queues to finish processing commands - _device->wait(); - } - - void Renderer::enumerate_extensions() { - // Get supported extensions - _extensions = _display.get().get_vulkan_extensions(); - -#ifdef DYN_DEBUG - // Enable validation layers on debug mode - _validation_layers.push_back("VK_LAYER_KHRONOS_validation"); - _extensions.push_back("VK_EXT_debug_utils"); - Log::info("--- Vulkan Extensions ---"); - for (const i8 *extension : _extensions) { - Log::info("* {}", extension); - } - Log::info(""); -#endif - } - - b8 Renderer::is_supporting_layers() { - auto layer_properties = vk::enumerateInstanceLayerProperties(); - for (const i8 *requested : _validation_layers) { - for (vk::LayerProperties &available : layer_properties) { - if (!std::strcmp(requested, available.layerName)) { - return true; - } - } - } - return false; - } - - void Renderer::create_instance() { -#ifdef DYN_DEBUG - if (!is_supporting_layers()) { - Log::error("Requested Vulkan validation layers unavailable."); - } -#endif - - // Setup the application and Vulkan instance - vk::ApplicationInfo app_info; - app_info.pApplicationName = _display.get().get_title().c_str(); - app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0); - app_info.pEngineName = "Dynamo Engine"; - app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0); - app_info.apiVersion = VK_MAKE_VERSION(1, 3, 0); - - vk::InstanceCreateInfo instance_info; - instance_info.pApplicationInfo = &app_info; - - // Load validation layers - instance_info.enabledLayerCount = _validation_layers.size(); - instance_info.ppEnabledLayerNames = _validation_layers.data(); - - // Load extensions - instance_info.enabledExtensionCount = _extensions.size(); - instance_info.ppEnabledExtensionNames = _extensions.data(); - -#ifdef DYN_DEBUG - // Include more validation layers on debug mode - std::vector layer_extensions = { - vk::ValidationFeatureEnableEXT::eBestPractices, - vk::ValidationFeatureEnableEXT::eDebugPrintf, - }; - vk::ValidationFeaturesEXT features_info(layer_extensions); - instance_info.pNext = &features_info; -#endif - - // Create the instance and debugger - _instance = vk::createInstanceUnique(instance_info); - _debugger = std::make_unique(*_instance); - } - - void Renderer::create_surface() { - _surface = vk::UniqueSurfaceKHR( - _display.get().get_vulkan_surface(_instance.get()), - _instance.get()); - } - - void Renderer::create_device() { - // Get the list of physical devices - std::vector physical_devices; - for (vk::PhysicalDevice vkd : _instance->enumeratePhysicalDevices()) { - PhysicalDevice physical(vkd, _surface.get()); - if (physical.calculate_score() > 0) { - physical_devices.emplace_back(physical); - } - } - if (physical_devices.empty()) { - Log::error("Failed to identify a Vulkan physical device."); - } - - // Select the device with the highest score - _device = std::make_unique(*std::max_element( - physical_devices.begin(), - physical_devices.end(), - [&](const PhysicalDevice &a, const PhysicalDevice &b) { - return a.calculate_score() < b.calculate_score(); - })); - _sampler = std::make_unique(*_device, 3); - -#ifdef DYN_DEBUG - Log::info("--- Vulkan Physical Devices ---"); - for (PhysicalDevice &device : physical_devices) { - if (device.get_handle() == _device->get_physical().get_handle()) { - Log::info("* {} | Score: {} [Selected]", - device.get_name(), - device.calculate_score()); - } else { - Log::info("* {} | Score: {}", - device.get_name(), - device.calculate_score()); - } - } - Log::info(""); -#endif - } - - void Renderer::create_pools() { - _memory_pool = std::make_unique(*_device); - _descriptor_pool = std::make_unique(*_device); - _graphics_command_pool = - std::make_unique(*_device, QueueFamily::Graphics); - _transfer_command_pool = - std::make_unique(*_device, QueueFamily::Transfer); - } - - void Renderer::create_swapchain() { - _swapchain = std::make_unique(*_device, _display, *_surface); - } - - void Renderer::create_synchronizers() { - _signal_image_ready.clear(); - _signal_render_done.clear(); - _fences.clear(); - - for (u32 i = 0; i < _max_frames_processing; i++) { - _signal_image_ready.push_back( - std::make_unique(*_device)); - _signal_render_done.push_back( - std::make_unique(*_device)); - _fences.push_back(std::make_unique(*_device)); - } - } - - void Renderer::create_depth_buffer() { - vk::Extent2D extent = _swapchain->get_extent(); - _depth_image = std::make_unique( - *_device, - *_memory_pool, - extent.width, - extent.height, - 1, - 1, - 1, - _device->get_physical().get_depth_format(), - vk::ImageType::e2D, - vk::ImageTiling::eOptimal, - vk::ImageUsageFlagBits::eDepthStencilAttachment, - _device->get_physical().get_msaa_samples()); - _depth_view = - std::make_unique(*_depth_image, - vk::ImageViewType::e2D, - vk::ImageAspectFlagBits::eDepth, - 1); - } - - void Renderer::create_color_buffer() { - vk::Extent2D extent = _swapchain->get_extent(); - _color_image = std::make_unique( - *_device, - *_memory_pool, - extent.width, - extent.height, - 1, - 1, - 1, - _swapchain->get_format().format, - vk::ImageType::e2D, - vk::ImageTiling::eOptimal, - vk::ImageUsageFlagBits::eColorAttachment, - _device->get_physical().get_msaa_samples()); - _color_view = - std::make_unique(*_color_image, - vk::ImageViewType::e2D, - vk::ImageAspectFlagBits::eColor, - 1); - } - - void Renderer::create_framebuffers() { - _renderpass = std::make_unique(*_device, *_swapchain); - vk::Extent2D extent = _swapchain->get_extent(); - - _framebuffers.clear(); - for (const std::unique_ptr &view : _swapchain->get_views()) { - _framebuffers.push_back(std::make_unique(*_device, - extent, - *_renderpass, - *_color_view, - *_depth_view, - *view)); - } - } - - void Renderer::create_pipeline() { - // Default shaders - _vertex_shader = - std::make_unique(*_device, - "vert.spv", - vk::ShaderStageFlagBits::eVertex); - _fragment_shader = - std::make_unique(*_device, - "frag.spv", - vk::ShaderStageFlagBits::eFragment); - - // Create the pipeline and allocate the descriptors - ShaderList shaders = { - *_vertex_shader, - *_fragment_shader, - }; - _pipeline_layout = std::make_unique(*_device, shaders); - _pipeline = - std::make_unique(*_device, - *_renderpass, - *_swapchain, - *_pipeline_layout, - vk::PrimitiveTopology::eTriangleList, - vk::PolygonMode::eFill); - _descriptor_pool->allocate(*_pipeline_layout, *_swapchain); - } - - void Renderer::create_command_buffers() { - // Define the command queues - _graphics_queue = _device->get_queue(QueueFamily::Graphics); - _transfer_queue = _device->get_queue(QueueFamily::Transfer); - _present_queue = _device->get_queue(QueueFamily::Present); - - // Create command buffers for each family - _graphics_command_buffers = - _graphics_command_pool->allocate(vk::CommandBufferLevel::ePrimary, - _framebuffers.size()); - } - - void Renderer::create_buffers() { - // Staging buffer for memory copies - vk::MemoryPropertyFlags staging_memory_properties = - vk::MemoryPropertyFlagBits::eHostVisible | - vk::MemoryPropertyFlagBits::eHostCoherent | - vk::MemoryPropertyFlagBits::eHostCached; - vk::BufferUsageFlags staging_buffer_usage = - vk::BufferUsageFlagBits::eTransferSrc; - _staging_buffer = std::make_unique(*_device, - *_memory_pool, - *_transfer_command_pool, - _transfer_queue, - staging_buffer_usage, - staging_memory_properties); - - // Object mesh buffer - vk::MemoryPropertyFlags object_memory_properties = - vk::MemoryPropertyFlagBits::eDeviceLocal; - vk::BufferUsageFlags object_buffer_usage = - vk::BufferUsageFlagBits::eIndexBuffer | - vk::BufferUsageFlagBits::eVertexBuffer; - _object_buffer = std::make_unique(*_device, - *_memory_pool, - *_transfer_command_pool, - _transfer_queue, - object_buffer_usage, - object_memory_properties); - - // Uniform buffer - vk::MemoryPropertyFlags uniform_memory_properties = - vk::MemoryPropertyFlagBits::eHostVisible | - vk::MemoryPropertyFlagBits::eHostCoherent | - vk::MemoryPropertyFlagBits::eHostCached; - vk::BufferUsageFlags uniform_buffer_usage = - vk::BufferUsageFlagBits::eUniformBuffer; - _uniform_buffer = std::make_unique(*_device, - *_memory_pool, - *_transfer_command_pool, - _transfer_queue, - uniform_buffer_usage, - uniform_memory_properties); - } - - void Renderer::record_commands() { - _graphics_queue.waitIdle(); - _graphics_command_pool->reset( - vk::CommandPoolResetFlagBits::eReleaseResources); - - vk::Rect2D render_area; - render_area.offset.x = 0; - render_area.offset.y = 0; - render_area.extent = _swapchain->get_extent(); - - std::array clear_values = { - _color_clear, - _depth_clear, - }; - - vk::CommandBufferBeginInfo begin_info; - for (u32 i = 0; i < _framebuffers.size(); i++) { - // Start recording - _graphics_command_buffers[i]->begin(begin_info); - - // Start the render pass - vk::RenderPassBeginInfo render_begin_info; - render_begin_info.renderPass = _renderpass->get_handle(); - render_begin_info.framebuffer = _framebuffers[i]->get_handle(); - render_begin_info.renderArea = render_area; - render_begin_info.clearValueCount = clear_values.size(); - render_begin_info.pClearValues = clear_values.data(); - - _graphics_command_buffers[i]->beginRenderPass( - render_begin_info, - vk::SubpassContents::eInline); - - // Bind the command buffer to the graphics pipeline - _graphics_command_buffers[i]->bindPipeline( - vk::PipelineBindPoint::eGraphics, - _pipeline->get_handle()); - - // Stop recording - _graphics_command_buffers[i]->endRenderPass(); - _graphics_command_buffers[i]->end(); - } - } - - void Renderer::reset_swapchain() { - // Wait for all GPU processes to finish - _device->wait(); - - // Reset the views before image to prevent invalid references (segfault) - // TODO: Best to use shared_ptr or some custom refcount implementation - _depth_view.reset(); - _color_view.reset(); - - // Free the swapchain - _swapchain.reset(); - - // Recreate objects - create_swapchain(); - create_synchronizers(); - - create_depth_buffer(); - create_color_buffer(); - - create_framebuffers(); - create_pipeline(); - create_command_buffers(); - } - - Texture Renderer::create_texture(std::string filename) { - i32 width, height, channels; - stbi_uc *raw_data = stbi_load(filename.c_str(), - &width, - &height, - &channels, - STBI_rgb_alpha); - std::vector pixels(width * height * STBI_rgb_alpha); - std::copy(raw_data, raw_data + pixels.size(), pixels.data()); - stbi_image_free(raw_data); - - return Texture(pixels.data(), - width, - height, - *_device, - *_memory_pool, - *_staging_buffer, - *_graphics_command_pool, - _graphics_queue); - } - - void Renderer::clear(Color color) { - _color_clear.color.setFloat32(color.to_array()); - } - - void Renderer::refresh() { - // Record the command buffers - record_commands(); - - // Grab the next available swapchain image presentation target - std::optional acquired = - _swapchain->get_presentation_image(*_signal_image_ready[_frame]); - if (!acquired.has_value()) { - reset_swapchain(); - return; - } - u32 image_index = acquired.value(); - - // Wait for the fence to finish and reset before proceeding - _fences[_frame]->wait(); - _fences[_frame]->reset(); - - // Submit commands to the graphics queue for rendering to that image - vk::PipelineStageFlags wait_stage = - vk::PipelineStageFlagBits::eColorAttachmentOutput; - vk::SubmitInfo submit_info; - submit_info.pWaitDstStageMask = &wait_stage; - submit_info.waitSemaphoreCount = 1; - submit_info.pWaitSemaphores = - &_signal_image_ready[_frame]->get_handle(); - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = - &_graphics_command_buffers[image_index].get(); - submit_info.signalSemaphoreCount = 1; - submit_info.pSignalSemaphores = - &_signal_render_done[_frame]->get_handle(); - - // Render to the target attachment and signal the current fence - _graphics_queue.submit(submit_info, _fences[_frame]->get_handle()); - - // Present rendered image to the display - vk::PresentInfoKHR present_info; - present_info.waitSemaphoreCount = 1; - present_info.pWaitSemaphores = - &_signal_render_done[_frame]->get_handle(); - present_info.swapchainCount = 1; - present_info.pSwapchains = &_swapchain->get_handle(); - present_info.pImageIndices = &image_index; - - try { - vk::Result result = _present_queue.presentKHR(present_info); - - // Sometimes, it does not throw an error - if (result != vk::Result::eSuccess) { - reset_swapchain(); - } - } catch (vk::OutOfDateKHRError &e) { - reset_swapchain(); - } - - // Advance the frame - _frame = (_frame + 1) % _max_frames_processing; - } -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Renderer.hpp b/src/Graphics/Vulkan/Renderer.hpp deleted file mode 100644 index 66980c3e..00000000 --- a/src/Graphics/Vulkan/Renderer.hpp +++ /dev/null @@ -1,255 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include - -#include "../../Log/Log.hpp" -#include "../../Types.hpp" -#include "../Renderer.hpp" -#include "./Core/Buffer.hpp" -#include "./Core/CommandPool.hpp" -#include "./Core/Debugger.hpp" -#include "./Core/DescriptorPool.hpp" -#include "./Core/Device.hpp" -#include "./Core/Fence.hpp" -#include "./Core/Framebuffer.hpp" -#include "./Core/Image.hpp" -#include "./Core/MemoryPool.hpp" -#include "./Core/PhysicalDevice.hpp" -#include "./Core/Pipeline.hpp" -#include "./Core/PipelineLayout.hpp" -#include "./Core/RenderPass.hpp" -#include "./Core/Sampler.hpp" -#include "./Core/Semaphore.hpp" -#include "./Core/ShaderModule.hpp" -#include "./Core/Swapchain.hpp" -#include "./Core/Texture.hpp" - -namespace Dynamo::Graphics::Vulkan { - /** - * @brief Renderer powered by the Vulkan API. - * - */ - class Renderer { - std::reference_wrapper _display; - - vk::UniqueInstance _instance; - vk::UniqueSurfaceKHR _surface; - - std::unique_ptr _device; - std::unique_ptr _sampler; - - std::unique_ptr _swapchain; - - // Pools - std::unique_ptr _memory_pool; - std::unique_ptr _descriptor_pool; - std::unique_ptr _graphics_command_pool; - std::unique_ptr _transfer_command_pool; - - // Framebuffers - std::unique_ptr _depth_image; - std::unique_ptr _depth_view; - - std::unique_ptr _color_image; - std::unique_ptr _color_view; - - std::unique_ptr _renderpass; - std::vector> _framebuffers; - - // Graphics pipeline - std::unique_ptr _vertex_shader; - std::unique_ptr _fragment_shader; - std::unique_ptr _pipeline_layout; - std::unique_ptr _pipeline; - - // Command buffers and queues - vk::Queue _graphics_queue; - vk::Queue _transfer_queue; - vk::Queue _present_queue; - - std::vector _graphics_command_buffers; - - // Buffers - std::unique_ptr _staging_buffer; - std::unique_ptr _object_buffer; - std::unique_ptr _uniform_buffer; - - // Synchronizers - // Semaphores synchronize the graphic and present commands - std::vector> _signal_image_ready; - std::vector> _signal_render_done; - - // Fences synchronize the GPU and CPU processes - std::vector> _fences; - - // Clear values - vk::ClearValue _color_clear; - vk::ClearValue _depth_clear; - - // Frame counters - u32 _frame = 0; - u32 _max_frames_processing = 3; - - /** - * @brief Debugger - * - */ - std::unique_ptr _debugger; - - /** - * @brief List of supported extensions - * - */ - std::vector _extensions; - - /** - * @brief List of enabled validation layers for debugging - * - */ - std::vector _validation_layers; - - /** - * @brief Enumerate all the supported extensions - * - */ - void enumerate_extensions(); - - /** - * @brief Check if the system supports the enabled validation layers - * - * @return true - * @return false - */ - b8 is_supporting_layers(); - - /** - * @brief Create a new vk::UniqueInstance - * - */ - void create_instance(); - - /** - * @brief Attach the Display to a vk::Surface - * - */ - void create_surface(); - - /** - * @brief Select a suitable hardware device and create the logical - * device - * - */ - void create_device(); - - /** - * @brief Create the synchronizer objects - * - */ - void create_synchronizers(); - - /** - * @brief Create the swapchain - * - */ - void create_swapchain(); - - /** - * @brief Create the image sampler - * - */ - void create_sampler(); - - /** - * @brief Create the allocators - * - */ - void create_pools(); - - /** - * @brief Create the depth buffer - * - */ - void create_depth_buffer(); - - /** - * @brief Create the color buffer - * - */ - void create_color_buffer(); - - /** - * @brief Create the framebuffers for each swapchain view - * - */ - void create_framebuffers(); - - /** - * @brief Create the graphics pipeline - * - */ - void create_pipeline(); - - /** - * @brief Create a command buffers - * - */ - void create_command_buffers(); - - /** - * @brief Create the buffers for reading and writing data to the GPU - * - */ - void create_buffers(); - - /** - * @brief Record the draw commands - * - */ - void record_commands(); - - /** - * @brief Reset the swapchain - * - */ - void reset_swapchain(); - - public: - /** - * @brief Construct a new Renderer object - * - * @param display - */ - Renderer(Display &display); - - /** - * @brief Destroy the Renderer object - * - */ - ~Renderer(); - - /** - * @brief Create a texture from an image file - * - * @param filename - * @return Texture - */ - Texture create_texture(std::string filename); - - /** - * @brief Clear the display with a color - * - */ - void clear(Color color); - - /** - * @brief Update the renderer and present to the display surface - * - */ - void refresh(); - }; -} // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/Shaders/base.frag b/src/Graphics/Vulkan/Shaders/base.frag deleted file mode 100644 index 9a9313c0..00000000 --- a/src/Graphics/Vulkan/Shaders/base.frag +++ /dev/null @@ -1,18 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects : enable - -layout(set = 0, binding = 1) uniform sampler2D textureSampler; - -layout(location = 0) in vec4 fragColor; -layout(location = 1) in vec2 fragTexCoord; - -layout(location = 0) out vec4 outColor; - -void main() { - vec4 texture = texture(textureSampler, fragTexCoord); - vec4 color = fragColor.rgba * texture.rgba; - - // Discard the fragment if it is translucent - if(color.a < 0.9) discard; - else outColor = color; -} \ No newline at end of file diff --git a/src/Graphics/Vulkan/Shaders/base.vert b/src/Graphics/Vulkan/Shaders/base.vert deleted file mode 100644 index 0edb2d9b..00000000 --- a/src/Graphics/Vulkan/Shaders/base.vert +++ /dev/null @@ -1,27 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects:enable - -layout(set=0,binding=0)uniform UniformBufferObject{ - mat4 transform; -}ubo; - -layout(push_constant)uniform ObjectData{ - int xOffset; - int yOffset; - int width; - int height; -}PushConstant; - -layout(location=0)in vec3 inPosition; -layout(location=1)in vec4 inColor; -layout(location=2)in vec2 inTexCoord; - -layout(location=0)out vec4 fragColor; -layout(location=1)out vec2 fragTexCoord; - -// gl_VertexIndex is the current vertex being read by the renderer! -void main(){ - gl_Position=ubo.transform*vec4(inPosition,1.); - fragColor=inColor; - fragTexCoord=inTexCoord; -} \ No newline at end of file diff --git a/src/Input.cpp b/src/Input.cpp new file mode 100644 index 00000000..0d8d9f98 --- /dev/null +++ b/src/Input.cpp @@ -0,0 +1,116 @@ +#include "Input.hpp" + +namespace Dynamo { + Input::Input(GLFWwindow *window) : _window(window) { + // Register input handling callbacks to update internal state + glfwSetWindowUserPointer(_window, &_state); + + // On cursor motion + auto cursor_cb = [](GLFWwindow *window, double x, double y) { + void *userptr = glfwGetWindowUserPointer(window); + InputState *state = static_cast(userptr); + state->mouse_position.x = x; + state->mouse_position.y = y; + }; + glfwSetCursorPosCallback(_window, cursor_cb); + + // On scroll + auto scroll_cb = [](GLFWwindow *window, double x, double y) { + void *userptr = glfwGetWindowUserPointer(window); + InputState *state = static_cast(userptr); + state->scroll_offset.x = x; + state->scroll_offset.y = y; + }; + glfwSetScrollCallback(_window, scroll_cb); + + // On key state change + auto key_cb = [](GLFWwindow *window, + int key, + int scancode, + int action, + int mods) { + void *userptr = glfwGetWindowUserPointer(window); + InputState *state = static_cast(userptr); + switch (action) { + case GLFW_PRESS: + state->key_pressed.insert(static_cast(key)); + break; + case GLFW_RELEASE: + state->key_released.insert(static_cast(key)); + break; + default: + break; + } + }; + glfwSetKeyCallback(_window, key_cb); + + // On mouse button state change + auto click_cb = [](GLFWwindow *window, + int button, + int action, + int mods) { + void *userptr = glfwGetWindowUserPointer(window); + InputState *state = static_cast(userptr); + switch (action) { + case GLFW_PRESS: + state->mouse_pressed.insert(static_cast(button)); + break; + case GLFW_RELEASE: + state->mouse_released.insert(static_cast(button)); + break; + default: + break; + } + }; + glfwSetMouseButtonCallback(_window, click_cb); + } + + const Vec2 &Input::get_mouse_position() const { + return _state.mouse_position; + } + + const Vec2 &Input::get_scroll_offset() const { + return _state.scroll_offset; + } + + bool Input::is_pressed(KeyCode code) { + return _state.key_pressed.count(code); + } + + bool Input::is_pressed(MouseCode code) { + return _state.mouse_pressed.count(code); + } + + bool Input::is_released(KeyCode code) { + return _state.key_released.count(code); + } + + bool Input::is_released(MouseCode code) { + return _state.mouse_released.count(code); + } + + bool Input::is_down(KeyCode code) { + return glfwGetKey(_window, static_cast(code)) == GLFW_PRESS; + } + + bool Input::is_down(MouseCode code) { + return glfwGetMouseButton(_window, static_cast(code)) == + GLFW_PRESS; + } + + void Input::poll() { + // Reset scroll state + _state.scroll_offset.x = 0; + _state.scroll_offset.y = 0; + + // Reset key states + _state.key_pressed.clear(); + _state.key_released.clear(); + + // Reset mouse button states + _state.mouse_pressed.clear(); + _state.mouse_released.clear(); + + glfwPollEvents(); + } +} // namespace Dynamo \ No newline at end of file diff --git a/src/Core/Input.hpp b/src/Input.hpp similarity index 92% rename from src/Core/Input.hpp rename to src/Input.hpp index 7f62ebca..e172afa6 100644 --- a/src/Core/Input.hpp +++ b/src/Input.hpp @@ -1,13 +1,10 @@ #pragma once -#include #include #include -#include "../Math/Vec2.hpp" -#include "../Types.hpp" -#include "Display.hpp" +#include "./Math/Vec2.hpp" namespace Dynamo { /** @@ -152,7 +149,7 @@ namespace Dynamo { * */ class Input { - std::reference_wrapper _display; + GLFWwindow *_window; struct InputState { Vec2 mouse_position; @@ -170,9 +167,9 @@ namespace Dynamo { /** * @brief Construct a new Input object * - * @param display + * @param window */ - Input(Display &display); + Input(GLFWwindow *window); /** * @brief Get the current mouse position @@ -199,7 +196,7 @@ namespace Dynamo { * @return true * @return false */ - b8 is_pressed(KeyCode code); + bool is_pressed(KeyCode code); /** * @brief Is the mouse button pressed? @@ -211,7 +208,7 @@ namespace Dynamo { * @return true * @return false */ - b8 is_pressed(MouseCode code); + bool is_pressed(MouseCode code); /** * @brief Is the key released? @@ -223,7 +220,7 @@ namespace Dynamo { * @return true * @return false */ - b8 is_released(KeyCode code); + bool is_released(KeyCode code); /** * @brief Is the mouse button released? @@ -235,7 +232,7 @@ namespace Dynamo { * @return true * @return false */ - b8 is_released(MouseCode code); + bool is_released(MouseCode code); /** * @brief Is the key held down? @@ -244,7 +241,7 @@ namespace Dynamo { * @return true * @return false */ - b8 is_down(KeyCode code); + bool is_down(KeyCode code); /** * @brief Is the mouse button held down? @@ -253,7 +250,7 @@ namespace Dynamo { * @return true * @return false */ - b8 is_down(MouseCode code); + bool is_down(MouseCode code); /** * @brief Poll input and update internal state diff --git a/src/Log/Log.cpp b/src/Log/Log.cpp deleted file mode 100644 index 30f2f5b3..00000000 --- a/src/Log/Log.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "Log.hpp" - -namespace Dynamo { - void Log::dump() { - auto timestamp = std::chrono::floor( - std::chrono::system_clock::now()); - std::string filename = - fmt::format("Dynamo_{:%Y-%m-%d_%H-%M-%S}.log", timestamp); - - std::ofstream outfile; - outfile.open(filename, std::ios::out); - - for (Message &message : _history) { - std::string formatted = message.format(); - outfile.write(formatted.c_str(), formatted.length()); - outfile.write("\n", 1); - } - } -} // namespace Dynamo \ No newline at end of file diff --git a/src/Log/Log.hpp b/src/Log/Log.hpp deleted file mode 100644 index 17be71dc..00000000 --- a/src/Log/Log.hpp +++ /dev/null @@ -1,94 +0,0 @@ -#pragma once -#ifndef NDEBUG -#define DYN_DEBUG -#endif - -#ifdef DYN_DEBUG -#define DYN_ASSERT(cond) \ - !(cond) ? Dynamo::Log::error("Assertion {} failed: {}, Line {}", \ - #cond, \ - __FILE__, \ - __LINE__) \ - : (void(0)) -#else -#define DYN_ASSERT(cond) (void(0)) -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "Message.hpp" - -namespace Dynamo { - /** - * @brief Logging utility handler. - * - */ - class Log { - inline static std::vector _history; - - public: - /** - * @brief Log an informative message to stdout. - * - * @param format Formatting template string. - * @param args Data arguments. - */ - template - static void info(std::string format = "", Types... args) { - const auto timestamp = std::chrono::system_clock::now(); - std::string content = fmt::format(format, args...); - Message message = {timestamp, content, MessageType::Info}; - _history.push_back(message); - std::cout << message.format() << std::endl; - } - - /** - * @brief Log an error to stderr and terminate the process. - * - * @param format Formatting template string. - * @param args Data arguments. - */ - template - static void error(std::string format, Types... args) { - const auto timestamp = std::chrono::system_clock::now(); - std::string content = fmt::format(format, args...); - Message message = {timestamp, content, MessageType::Error}; - _history.push_back(message); - std::cerr << message.format() << std::endl; - - // Terminate and write the log to disk - dump(); - throw std::runtime_error("Dynamo has crashed."); - } - - /** - * @brief Log a warning to stderr. - * - * @param format Formatting template string. - * @param args Data arguments. - */ - template - static void warn(std::string format, Types... args) { - const auto timestamp = std::chrono::system_clock::now(); - std::string content = fmt::format(format, args...); - Message message = {timestamp, content, MessageType::Warning}; - _history.push_back(message); - std::cerr << message.format() << std::endl; - } - - /** - * @brief Dump the log history to disk. - * - */ - static void dump(); - }; -} // namespace Dynamo diff --git a/src/Log/Message.cpp b/src/Log/Message.cpp deleted file mode 100644 index 7d024319..00000000 --- a/src/Log/Message.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "Message.hpp" - -namespace Dynamo { - std::string Message::format() { - switch (type) { - case MessageType::Error: - return fmt::format("[ERROR {:%Y-%m-%d %H:%M:%S}] {}", - timestamp, - content); - break; - case MessageType::Warning: - return fmt::format("[WARN {:%Y-%m-%d %H:%M:%S}] {}", - timestamp, - content); - break; - default: - return fmt::format("[INFO {:%Y-%m-%d %H:%M:%S}] {}", - timestamp, - content); - break; - } - } -} // namespace Dynamo \ No newline at end of file diff --git a/src/Log/Message.hpp b/src/Log/Message.hpp deleted file mode 100644 index 6127e41a..00000000 --- a/src/Log/Message.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include -#include - -#include -#include - -namespace Dynamo { - /** - * @brief Enumerates the different warning types. - * - */ - enum class MessageType { Info, Warning, Error }; - - /** - * @brief Message object. - * - */ - struct Message { - std::chrono::system_clock::time_point timestamp; - std::string content; - MessageType type; - - /** - * @brief Get the string representation of the message. - * - * @return std::string - */ - std::string format(); - }; -} // namespace Dynamo diff --git a/src/Math/Box2.hpp b/src/Math/Box2.hpp index fa801d7c..c47f6be0 100644 --- a/src/Math/Box2.hpp +++ b/src/Math/Box2.hpp @@ -2,7 +2,6 @@ #include -#include "../Types.hpp" #include "./Vec2.hpp" namespace Dynamo { @@ -29,7 +28,7 @@ namespace Dynamo { * @param width * @param height */ - Box2(Vec2 center, f32 width = 0, f32 height = 0) { + Box2(Vec2 center, float width = 0, float height = 0) { Vec2 halfdim(width * 0.5, height * 0.5); min = center - halfdim; max = center + halfdim; @@ -45,23 +44,23 @@ namespace Dynamo { /** * @brief Get the width of this box. * - * @return f32 + * @return float */ - inline f32 width() const { return max.x - min.x; } + inline float width() const { return max.x - min.x; } /** * @brief Get the height of this box. * - * @return f32 + * @return float */ - inline f32 height() const { return max.y - min.y; } + inline float height() const { return max.y - min.y; } /** * @brief Get the area of this box. * - * @return f32 + * @return float */ - inline f32 area() const { return width() * height(); } + inline float area() const { return width() * height(); } /** * @brief Translate this box by an offset vector. @@ -93,9 +92,9 @@ namespace Dynamo { * @return true * @return false */ - inline b8 intersects(const Box2 &box) const { - b8 h = max.x < box.min.x || min.x > box.max.x; - b8 v = max.y < box.min.y || min.y > box.max.y; + inline bool intersects(const Box2 &box) const { + bool h = max.x < box.min.x || min.x > box.max.x; + bool v = max.y < box.min.y || min.y > box.max.y; return !(h || v); } @@ -106,9 +105,9 @@ namespace Dynamo { * @return true * @return false */ - inline b8 contains(const Vec2 &point) const { - b8 h = point.x >= min.x && point.x <= max.x; - b8 v = point.y >= min.y && point.y <= max.y; + inline bool contains(const Vec2 &point) const { + bool h = point.x >= min.x && point.x <= max.x; + bool v = point.y >= min.y && point.y <= max.y; return h && v; } @@ -119,9 +118,9 @@ namespace Dynamo { * @return true * @return false */ - inline b8 contains(const Box2 &box) const { - b8 h = box.min.x >= min.x && box.max.x <= max.x; - b8 v = box.min.y >= min.y && box.max.y <= max.y; + inline bool contains(const Box2 &box) const { + bool h = box.min.x >= min.x && box.max.x <= max.x; + bool v = box.min.y >= min.y && box.max.y <= max.y; return h && v; } @@ -132,7 +131,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 operator==(const Box2 &rhs) const { + inline bool operator==(const Box2 &rhs) const { return min == rhs.min && max == rhs.max; } @@ -143,7 +142,9 @@ namespace Dynamo { * @return true * @return false */ - inline b8 operator!=(const Box2 &rhs) const { return !(*this == rhs); } + inline bool operator!=(const Box2 &rhs) const { + return !(*this == rhs); + } /** * @brief Test if the bounding volume is valid (min is less than max). @@ -151,7 +152,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 valid() const { return width() >= 0 && height() >= 0; } + inline bool valid() const { return width() >= 0 && height() >= 0; } }; } // namespace Dynamo diff --git a/src/Math/Circle.hpp b/src/Math/Circle.hpp index 01a3f342..8fca38d9 100644 --- a/src/Math/Circle.hpp +++ b/src/Math/Circle.hpp @@ -2,7 +2,6 @@ #include -#include "../Types.hpp" #include "./Vec2.hpp" namespace Dynamo { @@ -12,7 +11,7 @@ namespace Dynamo { */ struct Circle { Vec2 center; - f32 radius; + float radius; /** * @brief Construct a new Circle object. @@ -20,29 +19,29 @@ namespace Dynamo { * @param center * @param radius */ - constexpr Circle(Vec2 center = {}, f32 radius = 1) : + constexpr Circle(Vec2 center = {}, float radius = 1) : center(center), radius(radius) {} /** * @brief Get the circumference of this circle. * - * @return f32 + * @return float */ - inline f32 circumference() const { return 2 * M_PI * radius; } + inline float circumference() const { return 2 * M_PI * radius; } /** * @brief Get the diameter of this circle. * - * @return f32 + * @return float */ - inline f32 diameter() const { return 2 * radius; } + inline float diameter() const { return 2 * radius; } /** * @brief Get the area of this circle. * - * @return f32 + * @return float */ - inline f32 area() const { return M_PI * radius * radius; } + inline float area() const { return M_PI * radius * radius; } /** * @brief Test if this circle intersects with another circle. @@ -51,9 +50,9 @@ namespace Dynamo { * @return true * @return false */ - inline b8 intersects(const Circle &circle) const { - f32 r_sum = circle.radius + radius; - f32 d_sq = (circle.center - center).length_squared(); + inline bool intersects(const Circle &circle) const { + float r_sum = circle.radius + radius; + float d_sq = (circle.center - center).length_squared(); return d_sq <= r_sum * r_sum; } @@ -64,8 +63,8 @@ namespace Dynamo { * @return true * @return false */ - inline b8 contains(const Vec2 &point) const { - f32 d_sq = (point - center).length_squared(); + inline bool contains(const Vec2 &point) const { + float d_sq = (point - center).length_squared(); return d_sq <= radius * radius; } @@ -76,9 +75,9 @@ namespace Dynamo { * @return true * @return false */ - inline b8 contains(const Circle &circle) const { - f32 d_sq = (circle.center - center).length_squared(); - f32 r_diff = (circle.radius - radius); + inline bool contains(const Circle &circle) const { + float d_sq = (circle.center - center).length_squared(); + float r_diff = (circle.radius - radius); return d_sq <= r_diff * r_diff; } @@ -89,7 +88,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 operator==(const Circle &rhs) const { + inline bool operator==(const Circle &rhs) const { return radius == rhs.radius && center == rhs.center; } @@ -100,7 +99,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 operator!=(const Circle &rhs) const { + inline bool operator!=(const Circle &rhs) const { return !(*this == rhs); } @@ -110,7 +109,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 valid() const { return radius >= 0; } + inline bool valid() const { return radius >= 0; } }; } // namespace Dynamo @@ -123,7 +122,7 @@ template <> struct std::hash { inline size_t operator()(const Dynamo::Circle &circle) const { size_t tcenter = std::hash{}(circle.center); - size_t tradius = std::hash{}(circle.radius); + size_t tradius = std::hash{}(circle.radius); return tcenter ^ (tradius << 1); } }; diff --git a/src/Math/Color.hpp b/src/Math/Color.hpp index 31ca48be..bdae415c 100644 --- a/src/Math/Color.hpp +++ b/src/Math/Color.hpp @@ -2,7 +2,6 @@ #include -#include "../Types.hpp" #include "./Common.hpp" namespace Dynamo { @@ -14,10 +13,10 @@ namespace Dynamo { * */ struct Color { - f32 r; - f32 g; - f32 b; - f32 a; + float r; + float g; + float b; + float a; /** * @brief Construct a new Color object. @@ -27,7 +26,7 @@ namespace Dynamo { * @param b Blue channel. * @param a Alpha channel. */ - constexpr Color(f32 r = 0, f32 g = 0, f32 b = 0, f32 a = 1) : + constexpr Color(float r = 0, float g = 0, float b = 0, float a = 1) : r(r), g(g), b(b), a(a) {} /** @@ -37,7 +36,7 @@ namespace Dynamo { * @param t Interpolation factor. * @return Color */ - Color lerp(const Color &rhs, f32 t) const { + Color lerp(const Color &rhs, float t) const { return Color(Dynamo::lerp(r, rhs.r, t), Dynamo::lerp(g, rhs.g, t), Dynamo::lerp(b, rhs.b, t), @@ -55,22 +54,22 @@ namespace Dynamo { * @brief Convert the color to a single 32-bit unsigned integer which * can be represented as a hex value. * - * @return constexpr u32 + * @return constexpr unsigned */ - constexpr u32 to_hex() const { - u32 r_v = UINT8_MAX * r; - u32 g_v = UINT8_MAX * g; - u32 b_v = UINT8_MAX * b; - u32 a_v = UINT8_MAX * a; + constexpr unsigned to_hex() const { + unsigned r_v = UINT8_MAX * r; + unsigned g_v = UINT8_MAX * g; + unsigned b_v = UINT8_MAX * b; + unsigned a_v = UINT8_MAX * a; return (r_v << 24) | (g_v << 16) | (b_v << 8) | (a_v); } /** * @brief Convert the Color into an array of floats. * - * @return std::array + * @return std::array */ - std::array to_array() const { return {r, g, b, a}; } + std::array to_array() const { return {r, g, b, a}; } }; } // namespace Dynamo @@ -82,10 +81,10 @@ namespace Dynamo { template <> struct std::hash { inline size_t operator()(const Dynamo::Color &color) const { - Dynamo::i64 tr = color.r * 73856093; - Dynamo::i64 tg = color.g * 19349663; - Dynamo::i64 tb = color.b * 83492791; - Dynamo::i64 ta = color.a * 52477425; + long long tr = color.r * 73856093; + long long tg = color.g * 19349663; + long long tb = color.b * 83492791; + long long ta = color.a * 52477425; return tr ^ tg ^ tb ^ ta; } }; diff --git a/src/Math/Common.hpp b/src/Math/Common.hpp index 7a1fbbfc..4df5d6ee 100644 --- a/src/Math/Common.hpp +++ b/src/Math/Common.hpp @@ -1,20 +1,16 @@ #pragma once -#include - -#include "../Math/Vec2.hpp" -#include "../Math/Vec3.hpp" -#include "../Types.hpp" +constexpr double PI = 3.14159265358979323846264338327950288; namespace Dynamo { /** * @brief Convert an angle in radians to degrees. * * @param rad - * @return f32 + * @return float */ - inline f32 to_degrees(f32 rad) { - static const f32 factor = 180.0 / M_PI; + inline float to_degrees(float rad) { + static const float factor = 180.0 / PI; return rad * factor; } @@ -22,10 +18,10 @@ namespace Dynamo { * @brief Convert an angle in degrees to radians. * * @param deg - * @return f32 + * @return float */ - inline f32 to_radians(f32 deg) { - static const f32 factor = M_PI / 180.0; + inline float to_radians(float deg) { + static const float factor = PI / 180.0; return deg * factor; } @@ -35,7 +31,7 @@ namespace Dynamo { * @param a Start value. * @param b End value. * @param t Interpolation factor. - * @return f32 + * @return float */ - inline f32 lerp(f32 a, f32 b, f32 t) { return a + (b - a) * t; } + inline float lerp(float a, float b, float t) { return a + (b - a) * t; } } // namespace Dynamo \ No newline at end of file diff --git a/src/Math/Complex.hpp b/src/Math/Complex.hpp index 1f7f9506..7ea1607e 100644 --- a/src/Math/Complex.hpp +++ b/src/Math/Complex.hpp @@ -3,16 +3,14 @@ #include #include -#include "../Types.hpp" - namespace Dynamo { /** * @brief Complex number with real and imaginary components. * */ struct Complex { - f32 re; - f32 im; + float re; + float im; /** * @brief Construct a new Complex object. @@ -20,21 +18,21 @@ namespace Dynamo { * @param re Real part. * @param im Imaginary part. */ - constexpr Complex(f32 re = 0, f32 im = 0) : re(re), im(im) {} + constexpr Complex(float re = 0, float im = 0) : re(re), im(im) {} /** * @brief Calculate the square length. * - * @return f32 + * @return float */ - inline f32 length_squared() const { return re * re + im * im; } + inline float length_squared() const { return re * re + im * im; } /** * @brief Calculate the length. * - * @return f32 + * @return float */ - inline f32 length() const { return std::sqrt(length_squared()); } + inline float length() const { return std::sqrt(length_squared()); } /** * @brief Calculate the reciprocal of the complex number for use in @@ -43,7 +41,7 @@ namespace Dynamo { * @return Complex */ inline Complex reciprocal() const { - f32 scale = 1.0 / length_squared(); + float scale = 1.0 / length_squared(); return Complex(re * scale, -im * scale); } @@ -60,7 +58,7 @@ namespace Dynamo { * @return Complex */ inline Complex exp() const { - f32 scale = std::exp(re); + float scale = std::exp(re); return Complex(scale * std::cos(im), scale * std::sin(im)); } @@ -98,8 +96,8 @@ namespace Dynamo { * @return Complex */ inline Complex operator*(const Complex &rhs) const { - f32 n_re = re * rhs.re - im * rhs.im; - f32 n_im = re * rhs.im + im * rhs.re; + float n_re = re * rhs.re - im * rhs.im; + float n_im = re * rhs.im + im * rhs.re; return Complex(n_re, n_im); } @@ -109,7 +107,7 @@ namespace Dynamo { * @param scalar * @return Complex */ - inline Complex operator*(f32 scalar) const { + inline Complex operator*(float scalar) const { return Complex(scalar * re, scalar * im); } @@ -129,8 +127,8 @@ namespace Dynamo { * @param scalar * @return Complex */ - inline Complex operator/(f32 scalar) const { - f32 inv = 1.0 / scalar; + inline Complex operator/(float scalar) const { + float inv = 1.0 / scalar; return *this * inv; } @@ -165,8 +163,8 @@ namespace Dynamo { * @return Complex& */ inline Complex &operator*=(const Complex &rhs) { - f32 n_re = re * rhs.re - im * rhs.im; - f32 n_im = re * rhs.im + im * rhs.re; + float n_re = re * rhs.re - im * rhs.im; + float n_im = re * rhs.im + im * rhs.re; re = n_re; im = n_im; return *this; @@ -178,7 +176,7 @@ namespace Dynamo { * @param scalar * @return Complex& */ - inline Complex &operator*=(f32 scalar) { + inline Complex &operator*=(float scalar) { re *= scalar; im *= scalar; return *this; @@ -201,8 +199,8 @@ namespace Dynamo { * @param scalar * @return Complex& */ - inline Complex &operator/=(f32 scalar) { - f32 inv = 1.0 / scalar; + inline Complex &operator/=(float scalar) { + float inv = 1.0 / scalar; return *this *= inv; } @@ -213,7 +211,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 operator==(const Complex &rhs) const { + inline bool operator==(const Complex &rhs) const { return rhs.re == re && rhs.im == im; } @@ -224,7 +222,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 operator!=(const Complex &rhs) const { + inline bool operator!=(const Complex &rhs) const { return !(*this == rhs); } }; @@ -238,8 +236,8 @@ namespace Dynamo { template <> struct std::hash { inline size_t operator()(const Dynamo::Complex &complex) const { - Dynamo::i64 tre = complex.re * 73856093; - Dynamo::i64 tim = complex.im * 19349663; + long long tre = complex.re * 73856093; + long long tim = complex.im * 19349663; return tre ^ tim; } }; diff --git a/src/Math/Delaunay.cpp b/src/Math/Delaunay.cpp index 452eecfa..2d1aef26 100644 --- a/src/Math/Delaunay.cpp +++ b/src/Math/Delaunay.cpp @@ -1,4 +1,6 @@ -#include "Delaunay.hpp" +#include "./Delaunay.hpp" +#include "../Utils/Log.hpp" +#include "./Segment2.hpp" namespace Dynamo::Delaunay { std::vector triangulate(std::vector &points) { @@ -25,7 +27,7 @@ namespace Dynamo::Delaunay { triangles.push_back(super_triangle); // Edge buffer - std::unordered_map edges; + std::unordered_map edges; for (const Vec2 &point : points) { // Find triangles whose circumcircle contains the query point diff --git a/src/Math/Delaunay.hpp b/src/Math/Delaunay.hpp index ebc6848b..772f837e 100644 --- a/src/Math/Delaunay.hpp +++ b/src/Math/Delaunay.hpp @@ -1,21 +1,15 @@ #pragma once -#include -#include #include -#include "../Log/Log.hpp" -#include "../Types.hpp" #include "./Box2.hpp" -#include "./Circle.hpp" -#include "./Segment2.hpp" #include "./Triangle2.hpp" #include "./Vec2.hpp" namespace Dynamo::Delaunay { /** * @brief Calculate the delaunay triangulation of a point set. - * + * * This will reorder the points in-place for optimization purposes. * * @param points Input point set. diff --git a/src/Math/Fourier.cpp b/src/Math/Fourier.cpp index c946a454..06d60e87 100644 --- a/src/Math/Fourier.cpp +++ b/src/Math/Fourier.cpp @@ -1,12 +1,14 @@ #include "Fourier.hpp" +#include "../Utils/Bits.hpp" +#include "../Utils/Log.hpp" namespace Dynamo::Fourier { - void transform(Complex *signal, u32 N) { + void transform(Complex *signal, unsigned N) { DYN_ASSERT((N & (N - 1)) == 0); // Bit reversal element reordering - for (u32 i = 1, j = 0; i < N; i++) { - u32 bit = N >> 1; + for (unsigned i = 1, j = 0; i < N; i++) { + unsigned bit = N >> 1; while (bit & j) { j ^= bit; bit >>= 1; @@ -18,16 +20,16 @@ namespace Dynamo::Fourier { } // Radix-2 FFT - for (u32 s = 1; s <= find_lsb(N); s++) { - u32 m = 1 << s; - u32 half_m = m >> 1; + for (unsigned s = 1; s <= find_lsb(N); s++) { + unsigned m = 1 << s; + unsigned half_m = m >> 1; Complex omega_m = TWIDDLE_TABLE_FFT[s]; - for (u32 k = 0; k < N; k += m) { + for (unsigned k = 0; k < N; k += m) { Complex omega(1); - for (u32 j = 0; j < half_m; j++) { - u32 u_i = k + j; - u32 t_i = u_i + half_m; + for (unsigned j = 0; j < half_m; j++) { + unsigned u_i = k + j; + unsigned t_i = u_i + half_m; Complex t = omega * signal[t_i]; Complex u = signal[u_i]; signal[u_i] = u + t; @@ -38,12 +40,12 @@ namespace Dynamo::Fourier { } } - void inverse(Complex *signal, u32 N) { + void inverse(Complex *signal, unsigned N) { DYN_ASSERT((N & (N - 1)) == 0); // Bit reversal element reordering - for (u32 i = 1, j = 0; i < N; i++) { - u32 bit = N >> 1; + for (unsigned i = 1, j = 0; i < N; i++) { + unsigned bit = N >> 1; while (bit & j) { j ^= bit; bit >>= 1; @@ -55,16 +57,16 @@ namespace Dynamo::Fourier { } // Radix-2 IFFT - for (u32 s = 1; s <= find_lsb(N); s++) { - u32 m = 1 << s; - u32 half_m = m >> 1; + for (unsigned s = 1; s <= find_lsb(N); s++) { + unsigned m = 1 << s; + unsigned half_m = m >> 1; Complex omega_m = TWIDDLE_TABLE_IFFT[s]; - for (u32 k = 0; k < N; k += m) { + for (unsigned k = 0; k < N; k += m) { Complex omega(1); - for (u32 j = 0; j < half_m; j++) { - u32 u_i = k + j; - u32 t_i = u_i + half_m; + for (unsigned j = 0; j < half_m; j++) { + unsigned u_i = k + j; + unsigned t_i = u_i + half_m; Complex t = omega * signal[t_i]; Complex u = signal[u_i]; signal[u_i] = u + t; @@ -75,8 +77,8 @@ namespace Dynamo::Fourier { } // Normalize - f32 inv_N = 1.0 / N; - for (u32 f = 0; f < N; f++) { + float inv_N = 1.0 / N; + for (unsigned f = 0; f < N; f++) { signal[f] *= inv_N; } } diff --git a/src/Math/Fourier.hpp b/src/Math/Fourier.hpp index e7449395..a929268d 100644 --- a/src/Math/Fourier.hpp +++ b/src/Math/Fourier.hpp @@ -1,11 +1,6 @@ #pragma once #include -#include - -#include "../Log/Log.hpp" -#include "../Types.hpp" -#include "../Utils/Bits.hpp" #include "./Complex.hpp" @@ -16,10 +11,10 @@ namespace Dynamo::Fourier { * @param inverse Forward or inverse transform table. * @return std::array */ - static std::array construct_twiddle_table(b8 inverse) { + static std::array construct_twiddle_table(bool inverse) { std::array table; - f32 sign = inverse ? 1 : -1; - for (u32 i = 0; i < 32; i++) { + float sign = inverse ? 1 : -1; + for (unsigned i = 0; i < 32; i++) { table[i] = Complex(0, sign * 2 * M_PI / (1 << i)).exp(); } return table; @@ -46,7 +41,7 @@ namespace Dynamo::Fourier { * @param signal Signal buffer. * @param N Total number of frames (must be a power of 2). */ - void transform(Complex *signal, u32 N); + void transform(Complex *signal, unsigned N); /** * @brief Implementation of the inverse fourier transform algorithm to @@ -55,5 +50,5 @@ namespace Dynamo::Fourier { * @param signal Signal buffer. * @param N Total number of frames (must be a power of 2). */ - void inverse(Complex *signal, u32 N); + void inverse(Complex *signal, unsigned N); } // namespace Dynamo::Fourier \ No newline at end of file diff --git a/src/Math/Matrix.hpp b/src/Math/Matrix.hpp index 417c4216..2aed7d51 100644 --- a/src/Math/Matrix.hpp +++ b/src/Math/Matrix.hpp @@ -2,26 +2,24 @@ #include -#include "../Types.hpp" - namespace Dynamo { /** * @brief A square matrix. * * @tparam N Number of rows or columns. */ - template + template struct Matrix { - static constexpr u32 N2 = N * N; - std::array values; + static constexpr unsigned N2 = N * N; + std::array values; /** * @brief Construct a new Matrix object. * */ constexpr Matrix() { - for (u32 i = 0; i < N; i++) { - for (u32 j = 0; j < N; j++) { + for (unsigned i = 0; i < N; i++) { + for (unsigned j = 0; j < N; j++) { values[i * N + j] = (i == j); } } @@ -31,8 +29,8 @@ namespace Dynamo { * @brief Construct a new Matrix object. * */ - constexpr Matrix(f32 v) { - for (u32 i = 0; i < N2; i++) { + constexpr Matrix(float v) { + for (unsigned i = 0; i < N2; i++) { values[i] = v; } } @@ -44,7 +42,7 @@ namespace Dynamo { */ inline Matrix operator-() { Matrix result; - for (u32 i = 0; i < N2; i++) { + for (unsigned i = 0; i < N2; i++) { result.values[i] = -values[i]; } return result; @@ -58,7 +56,7 @@ namespace Dynamo { */ inline Matrix operator+(const Matrix &rhs) { Matrix result; - for (u32 i = 0; i < N2; i++) { + for (unsigned i = 0; i < N2; i++) { result.values[i] = values[i] + rhs.values[i]; } return result; @@ -72,7 +70,7 @@ namespace Dynamo { */ inline Matrix operator-(const Matrix &rhs) { Matrix result; - for (u32 i = 0; i < N2; i++) { + for (unsigned i = 0; i < N2; i++) { result.values[i] = values[i] - rhs.values[i]; } return result; @@ -86,10 +84,10 @@ namespace Dynamo { */ inline Matrix operator*(const Matrix &rhs) { Matrix result; - for (u32 i = 0; i < N; i++) { - for (u32 j = 0; j < N; j++) { - f32 dot = 0; - for (u32 c = 0; c < N; c++) { + for (unsigned i = 0; i < N; i++) { + for (unsigned j = 0; j < N; j++) { + float dot = 0; + for (unsigned c = 0; c < N; c++) { dot += values[i * N + c] * rhs.values[c * N + j]; } result.values[i * N + j] = dot; @@ -104,9 +102,9 @@ namespace Dynamo { * @param rhs * @return Matrix */ - inline Matrix operator*(f32 rhs) { + inline Matrix operator*(float rhs) { Matrix result; - for (u32 i = 0; i < N2; i++) { + for (unsigned i = 0; i < N2; i++) { result.values[i] = values[i] * rhs; } return result; @@ -118,8 +116,8 @@ namespace Dynamo { * @param rhs * @return Matrix */ - inline Matrix operator/(f32 rhs) { - f32 inv = 1.0 / rhs; + inline Matrix operator/(float rhs) { + float inv = 1.0 / rhs; return (*this) * inv; } @@ -130,7 +128,7 @@ namespace Dynamo { * @return Matrix */ inline Matrix &operator+=(const Matrix &rhs) { - for (u32 i = 0; i < N2; i++) { + for (unsigned i = 0; i < N2; i++) { values[i] += rhs.values[i]; } return *this; @@ -143,7 +141,7 @@ namespace Dynamo { * @return Matrix */ inline Matrix &operator-=(const Matrix &rhs) { - for (u32 i = 0; i < N2; i++) { + for (unsigned i = 0; i < N2; i++) { values[i] -= rhs.values[i]; } return *this; @@ -157,10 +155,10 @@ namespace Dynamo { */ inline Matrix &operator*=(const Matrix &rhs) { Matrix result; - for (u32 i = 0; i < N; i++) { - for (u32 j = 0; j < N; j++) { - f32 dot = 0; - for (u32 c = 0; c < N; c++) { + for (unsigned i = 0; i < N; i++) { + for (unsigned j = 0; j < N; j++) { + float dot = 0; + for (unsigned c = 0; c < N; c++) { dot += values[i * N + c] * rhs.values[c * N + j]; } result.values[i * N + j] = dot; @@ -176,8 +174,8 @@ namespace Dynamo { * @param rhs * @return Matrix */ - inline Matrix operator*=(f32 rhs) { - for (u32 i = 0; i < N2; i++) { + inline Matrix operator*=(float rhs) { + for (unsigned i = 0; i < N2; i++) { values[i] *= rhs; } return *this; @@ -189,8 +187,8 @@ namespace Dynamo { * @param rhs * @return Matrix */ - inline Matrix operator/=(f32 rhs) { - f32 inv = 1.0 / rhs; + inline Matrix operator/=(float rhs) { + float inv = 1.0 / rhs; return (*this) *= inv; } @@ -200,8 +198,8 @@ namespace Dynamo { * @return Matrix& */ inline Matrix &transpose() { - for (i32 i = 0; i < N; i++) { - for (i32 j = 0; j < N; j++) { + for (unsigned i = 0; i < N; i++) { + for (unsigned j = 0; j < N; j++) { std::swap(values[i + j * N], values[j + i * N]); } } @@ -215,8 +213,8 @@ namespace Dynamo { * @return true * @return false */ - inline b8 operator==(const Matrix &rhs) const { - for (u32 i = 0; i < N2; i++) { + inline bool operator==(const Matrix &rhs) const { + for (unsigned i = 0; i < N2; i++) { if (values[i] != rhs.values[i]) { return false; } @@ -231,7 +229,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 operator!=(const Matrix &rhs) const { + inline bool operator!=(const Matrix &rhs) const { return !(*this == rhs); } }; diff --git a/src/Math/Quaternion.hpp b/src/Math/Quaternion.hpp index a2f9c7a1..de3ad3c5 100644 --- a/src/Math/Quaternion.hpp +++ b/src/Math/Quaternion.hpp @@ -3,7 +3,6 @@ #include #include -#include "../Types.hpp" #include "./Vec3.hpp" namespace Dynamo { @@ -12,7 +11,7 @@ namespace Dynamo { * */ struct Quaternion { - f32 x, y, z, w; + float x, y, z, w; /** * @brief Construct a new Quaternion object. @@ -22,8 +21,12 @@ namespace Dynamo { * @param z Coefficient of k component. * @param w Scalar component. */ - constexpr Quaternion(f32 x = 0, f32 y = 0, f32 z = 0, f32 w = 1) : - x(x), y(y), z(z), w(w) {} + constexpr Quaternion(float x = 0, + float y = 0, + float z = 0, + float w = 1) : + x(x), + y(y), z(z), w(w) {} /** * @brief Construct a new Quaternion object from an angle-axis pair. @@ -31,9 +34,9 @@ namespace Dynamo { * @param axis Rotation axis. * @param angle Rotation angle in radians. */ - Quaternion(Vec3 axis, f32 angle) { - f32 half_angle = 0.5 * angle; - f32 sine = std::sin(half_angle); + Quaternion(Vec3 axis, float angle) { + float half_angle = 0.5 * angle; + float sine = std::sin(half_angle); x = axis.x * sine; y = axis.y * sine; z = axis.z * sine; @@ -43,18 +46,18 @@ namespace Dynamo { /** * @brief Calculate the square length. * - * @return f32 + * @return float */ - inline f32 length_squared() const { + inline float length_squared() const { return x * x + y * y + z * z + w * w; } /** * @brief Calculate the length. * - * @return f32 + * @return float */ - inline f32 length() const { return std::sqrt(length_squared()); } + inline float length() const { return std::sqrt(length_squared()); } /** * @brief Calculate the reciprocal of the quaternion for use in @@ -63,7 +66,7 @@ namespace Dynamo { * @return Quaternion */ inline Quaternion reciprocal() const { - f32 scale = 1.0 / length_squared(); + float scale = 1.0 / length_squared(); return Quaternion(-x * scale, -y * scale, -z * scale, w * scale); } @@ -114,10 +117,10 @@ namespace Dynamo { * @return Quaternion */ inline Quaternion operator*(const Quaternion &rhs) const { - f32 n_x = w * rhs.x + x * rhs.w + y * rhs.z - z * rhs.y; - f32 n_y = w * rhs.y - x * rhs.z + y * rhs.w + z * rhs.x; - f32 n_z = w * rhs.z + x * rhs.y - y * rhs.x + z * rhs.w; - f32 n_w = w * rhs.w - x * rhs.x - y * rhs.y - z * rhs.z; + float n_x = w * rhs.x + x * rhs.w + y * rhs.z - z * rhs.y; + float n_y = w * rhs.y - x * rhs.z + y * rhs.w + z * rhs.x; + float n_z = w * rhs.z + x * rhs.y - y * rhs.x + z * rhs.w; + float n_w = w * rhs.w - x * rhs.x - y * rhs.y - z * rhs.z; return Quaternion(n_x, n_y, n_z, n_w); } @@ -127,7 +130,7 @@ namespace Dynamo { * @param scalar * @return Quaternion */ - inline Quaternion operator*(f32 scalar) const { + inline Quaternion operator*(float scalar) const { return Quaternion(scalar * x, scalar * y, scalar * z, scalar * w); } @@ -137,8 +140,8 @@ namespace Dynamo { * @param scalar * @return Quaternion */ - inline Quaternion operator/(f32 scalar) const { - f32 inv = 1.0 / scalar; + inline Quaternion operator/(float scalar) const { + float inv = 1.0 / scalar; return Quaternion(inv * x, inv * y, inv * z, inv * w); } @@ -179,10 +182,10 @@ namespace Dynamo { * @return Quaternion */ inline Quaternion &operator*=(const Quaternion &rhs) { - f32 n_x = w * rhs.x + x * rhs.w + y * rhs.z - z * rhs.y; - f32 n_y = w * rhs.y - x * rhs.z + y * rhs.w + z * rhs.x; - f32 n_z = w * rhs.z + x * rhs.y - y * rhs.x + z * rhs.w; - f32 n_w = w * rhs.w - x * rhs.x - y * rhs.y - z * rhs.z; + float n_x = w * rhs.x + x * rhs.w + y * rhs.z - z * rhs.y; + float n_y = w * rhs.y - x * rhs.z + y * rhs.w + z * rhs.x; + float n_z = w * rhs.z + x * rhs.y - y * rhs.x + z * rhs.w; + float n_w = w * rhs.w - x * rhs.x - y * rhs.y - z * rhs.z; x = n_x; y = n_y; z = n_z; @@ -196,7 +199,7 @@ namespace Dynamo { * @param scalar * @return Quaternion */ - inline Quaternion &operator*=(f32 scalar) { + inline Quaternion &operator*=(float scalar) { x *= scalar; y *= scalar; z *= scalar; @@ -210,8 +213,8 @@ namespace Dynamo { * @param scalar * @return Quaternion */ - inline Quaternion &operator/=(f32 scalar) { - f32 inv = 1.0 / scalar; + inline Quaternion &operator/=(float scalar) { + float inv = 1.0 / scalar; return *this *= inv; } @@ -240,9 +243,9 @@ namespace Dynamo { * @return Vec3 */ inline Vec3 forward() const { - f32 n_x = 2 * (x * z + w * y); - f32 n_y = 2 * (y * z - w * x); - f32 n_z = 1 - 2 * (x * x + y * y); + float n_x = 2 * (x * z + w * y); + float n_y = 2 * (y * z - w * x); + float n_z = 1 - 2 * (x * x + y * y); return Vec3(n_x, n_y, n_z); } @@ -252,9 +255,9 @@ namespace Dynamo { * @return Vec3 */ inline Vec3 up() const { - f32 n_x = 2 * (x * y - w * z); - f32 n_y = 1 - 2 * (x * x + z * z); - f32 n_z = 2 * (y * z + w * x); + float n_x = 2 * (x * y - w * z); + float n_y = 1 - 2 * (x * x + z * z); + float n_z = 2 * (y * z + w * x); return Vec3(n_x, n_y, n_z); } @@ -264,9 +267,9 @@ namespace Dynamo { * @return Vec3 */ inline Vec3 right() const { - f32 n_x = 1 - 2 * (y * y + z * z); - f32 n_y = 2 * (x * y + w * z); - f32 n_z = 2 * (x * z - w * y); + float n_x = 1 - 2 * (y * y + z * z); + float n_y = 2 * (x * y + w * z); + float n_z = 2 * (x * z - w * y); return Vec3(n_x, n_y, n_z); } @@ -277,7 +280,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 operator==(const Quaternion &rhs) const { + inline bool operator==(const Quaternion &rhs) const { return x == rhs.x && y == rhs.y && z == rhs.z && w == rhs.w; } @@ -288,7 +291,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 operator!=(const Quaternion &rhs) const { + inline bool operator!=(const Quaternion &rhs) const { return !(*this == rhs); } }; @@ -302,10 +305,10 @@ namespace Dynamo { template <> struct std::hash { inline size_t operator()(const Dynamo::Quaternion &quaternion) const { - Dynamo::i64 tx = quaternion.x * 73856093; - Dynamo::i64 ty = quaternion.y * 19349663; - Dynamo::i64 tz = quaternion.z * 83492791; - Dynamo::i64 tw = quaternion.w * 52477425; + long long tx = quaternion.x * 73856093; + long long ty = quaternion.y * 19349663; + long long tz = quaternion.z * 83492791; + long long tw = quaternion.w * 52477425; return tx ^ ty ^ tz ^ tw; } }; diff --git a/src/Math/Segment2.hpp b/src/Math/Segment2.hpp index 1fa6fad1..eae6ab7b 100644 --- a/src/Math/Segment2.hpp +++ b/src/Math/Segment2.hpp @@ -2,7 +2,6 @@ #include -#include "../Types.hpp" #include "./Vec2.hpp" namespace Dynamo { @@ -24,16 +23,16 @@ namespace Dynamo { /** * @brief Calculate the squared length. * - * @return f32 + * @return float */ - inline f32 length_squared() const { return (a - b).length_squared(); } + inline float length_squared() const { return (a - b).length_squared(); } /** * @brief Calculate the length. * - * @return f32 + * @return float */ - inline f32 length() const { return (a - b).length(); } + inline float length() const { return (a - b).length(); } /** * @brief Equality operator. @@ -42,7 +41,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 operator==(const Segment2 &rhs) const { + inline bool operator==(const Segment2 &rhs) const { return (a == rhs.a && b == rhs.b) || (b == rhs.a && a == rhs.b); } @@ -53,7 +52,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 operator!=(const Segment2 &rhs) const { + inline bool operator!=(const Segment2 &rhs) const { return !(*this == rhs); } }; diff --git a/src/Math/Triangle2.hpp b/src/Math/Triangle2.hpp index 5c46fd23..c84ecab8 100644 --- a/src/Math/Triangle2.hpp +++ b/src/Math/Triangle2.hpp @@ -2,7 +2,6 @@ #include -#include "../Types.hpp" #include "./Circle.hpp" #include "./Vec2.hpp" #include "./Vec3.hpp" @@ -34,12 +33,12 @@ namespace Dynamo { Vec2 ab = b - a; Vec2 ac = c - a; - f32 inv_d = 1.0 / (ab.cross(ac) * 2.0); - f32 ab_sq = ab.length_squared(); - f32 ac_sq = ac.length_squared(); + float inv_d = 1.0 / (ab.cross(ac) * 2.0); + float ab_sq = ab.length_squared(); + float ac_sq = ac.length_squared(); - f32 ux = inv_d * (ac.y * ab_sq - ab.y * ac_sq); - f32 uy = inv_d * (ab.x * ac_sq - ac.x * ab_sq); + float ux = inv_d * (ac.y * ab_sq - ab.y * ac_sq); + float uy = inv_d * (ab.x * ac_sq - ac.x * ab_sq); Vec2 u(ux, uy); return Circle(a + u, u.length()); @@ -56,16 +55,16 @@ namespace Dynamo { Vec2 ac = c - a; Vec2 ap = point - a; - f32 d00 = ab * ab; - f32 d01 = ab * ac; - f32 d11 = ac * ac; - f32 d20 = ap * ab; - f32 d21 = ap * ac; - f32 inv = 1.0 / (d00 * d11 - d01 * d01); + float d00 = ab * ab; + float d01 = ab * ac; + float d11 = ac * ac; + float d20 = ap * ab; + float d21 = ap * ac; + float inv = 1.0 / (d00 * d11 - d01 * d01); - f32 v = (d11 * d20 - d01 * d21) * inv; - f32 w = (d00 * d21 - d01 * d20) * inv; - f32 u = 1.0 - (v + w); + float v = (d11 * d20 - d01 * d21) * inv; + float w = (d00 * d21 - d01 * d20) * inv; + float u = 1.0 - (v + w); return Vec3(u, v, w); } @@ -76,9 +75,9 @@ namespace Dynamo { * If the result is = 0, the points are collinear. * If the result is > 0, the points are anti-clockwise. * - * @return i32 + * @return int */ - inline i32 winding() const { + inline int winding() const { Vec2 ab = b - a; Vec2 ac = c - a; return ab.cross(ac); @@ -88,9 +87,9 @@ namespace Dynamo { * @brief Count the number of shared vertices with another triangle. * * @param rhs - * @return i32 + * @return unsigned */ - inline i32 shared_vertices(const Triangle2 &rhs) const { + inline unsigned shared_vertices(const Triangle2 &rhs) const { return (a == rhs.a) + (a == rhs.b) + (a == rhs.c) + (b == rhs.a) + (b == rhs.b) + (b == rhs.c) + (c == rhs.a) + (c == rhs.b) + (c == rhs.c); @@ -103,7 +102,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 adjacent(const Triangle2 &rhs) const { + inline bool adjacent(const Triangle2 &rhs) const { return shared_vertices(rhs) > 1; } @@ -114,7 +113,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 operator==(const Triangle2 &rhs) const { + inline bool operator==(const Triangle2 &rhs) const { return a == rhs.a && b == rhs.b && c == rhs.c; } @@ -125,7 +124,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 operator!=(const Triangle2 &rhs) const { + inline bool operator!=(const Triangle2 &rhs) const { return !(*this == rhs); } }; diff --git a/src/Math/Vec2.hpp b/src/Math/Vec2.hpp index 98a3def6..e0b4dc5e 100644 --- a/src/Math/Vec2.hpp +++ b/src/Math/Vec2.hpp @@ -3,7 +3,6 @@ #include #include -#include "../Types.hpp" #include "Matrix.hpp" namespace Dynamo { @@ -12,7 +11,7 @@ namespace Dynamo { * */ struct Vec2 { - f32 x, y; + float x, y; /** * @brief Construct a new Vec2 object. @@ -20,21 +19,21 @@ namespace Dynamo { * @param x * @param y */ - constexpr Vec2(f32 x = 0, f32 y = 0) : x(x), y(y) {} + constexpr Vec2(float x = 0, float y = 0) : x(x), y(y) {} /** * @brief Calculate the squared length. * - * @return f32 + * @return float */ - inline f32 length_squared() const { return x * x + y * y; } + inline float length_squared() const { return x * x + y * y; } /** * @brief Calculate the length. * - * @return f32 + * @return float */ - inline f32 length() const { return std::sqrt(length_squared()); } + inline float length() const { return std::sqrt(length_squared()); } /** * @brief Get the left normal perpendicular to this vector. @@ -76,7 +75,7 @@ namespace Dynamo { * @param scalar * @return Vec2 */ - inline Vec2 operator*(f32 scalar) const { + inline Vec2 operator*(float scalar) const { return Vec2(x * scalar, y * scalar); } @@ -86,8 +85,8 @@ namespace Dynamo { * @param scalar * @return Vec2 */ - inline Vec2 operator/(f32 scalar) const { - const f32 inv = 1.0f / scalar; + inline Vec2 operator/(float scalar) const { + const float inv = 1.0f / scalar; return *this * inv; } @@ -128,7 +127,7 @@ namespace Dynamo { * @param scalar * @return Vec2& */ - inline Vec2 &operator*=(f32 scalar) { + inline Vec2 &operator*=(float scalar) { x *= scalar; y *= scalar; return *this; @@ -140,8 +139,8 @@ namespace Dynamo { * @param scalar * @return Vec2& */ - inline Vec2 &operator/=(f32 scalar) { - f32 inv = 1.0 / scalar; + inline Vec2 &operator/=(float scalar) { + float inv = 1.0 / scalar; return *this *= inv; } @@ -160,7 +159,7 @@ namespace Dynamo { */ inline Vec2 &transform(const Mat3 &mat) { const auto &vals = mat.values; - f32 w = 1.0 / (vals[6] * x + vals[7] * y + vals[8]); + float w = 1.0 / (vals[6] * x + vals[7] * y + vals[8]); x = (vals[0] * x + vals[1] * y + vals[2]) * w; y = (vals[3] * x + vals[4] * y + vals[5]) * w; return *this; @@ -170,9 +169,9 @@ namespace Dynamo { * @brief Dot product. * * @param rhs - * @return f32 + * @return float */ - inline f32 operator*(const Vec2 &rhs) const { + inline float operator*(const Vec2 &rhs) const { return x * rhs.x + y * rhs.y; } @@ -180,9 +179,9 @@ namespace Dynamo { * @brief 2D cross product. * * @param rhs - * @return f32 + * @return float */ - inline f32 cross(const Vec2 &rhs) const { + inline float cross(const Vec2 &rhs) const { return x * rhs.y - y * rhs.x; } @@ -193,7 +192,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 operator==(const Vec2 &rhs) const { + inline bool operator==(const Vec2 &rhs) const { return x == rhs.x && y == rhs.y; } @@ -204,7 +203,9 @@ namespace Dynamo { * @return true * @return false */ - inline b8 operator!=(const Vec2 &rhs) const { return !(*this == rhs); } + inline bool operator!=(const Vec2 &rhs) const { + return !(*this == rhs); + } }; } // namespace Dynamo @@ -216,8 +217,8 @@ namespace Dynamo { template <> struct std::hash { inline size_t operator()(const Dynamo::Vec2 &point) const { - Dynamo::i64 tx = point.x * 73856093; - Dynamo::i64 ty = point.y * 19349663; + long long tx = point.x * 73856093; + long long ty = point.y * 19349663; return tx ^ ty; } }; diff --git a/src/Math/Vec3.hpp b/src/Math/Vec3.hpp index 6558c2d6..18177e09 100644 --- a/src/Math/Vec3.hpp +++ b/src/Math/Vec3.hpp @@ -3,7 +3,6 @@ #include #include -#include "../Types.hpp" #include "Matrix.hpp" namespace Dynamo { @@ -12,7 +11,7 @@ namespace Dynamo { * */ struct Vec3 { - f32 x, y, z; + float x, y, z; /** * @brief Construct a new Vec3 object. @@ -21,21 +20,22 @@ namespace Dynamo { * @param y * @param z */ - constexpr Vec3(f32 x = 0, f32 y = 0, f32 z = 0) : x(x), y(y), z(z) {} + constexpr Vec3(float x = 0, float y = 0, float z = 0) : + x(x), y(y), z(z) {} /** * @brief Calculate the squared length. * - * @return f32 + * @return float */ - inline f32 length_squared() const { return x * x + y * y + z * z; } + inline float length_squared() const { return x * x + y * y + z * z; } /** * @brief Calculate the length. * - * @return f32 + * @return float */ - inline f32 length() const { return std::sqrt(length_squared()); } + inline float length() const { return std::sqrt(length_squared()); } /** * @brief Add another vector. @@ -63,7 +63,7 @@ namespace Dynamo { * @param scalar * @return Vec3 */ - inline Vec3 operator*(f32 scalar) const { + inline Vec3 operator*(float scalar) const { return Vec3(x * scalar, y * scalar, z * scalar); } @@ -73,8 +73,8 @@ namespace Dynamo { * @param scalar * @return Vec3 */ - inline Vec3 operator/(f32 scalar) const { - f32 inv = 1.0f / scalar; + inline Vec3 operator/(float scalar) const { + float inv = 1.0f / scalar; return *this * inv; } @@ -117,7 +117,7 @@ namespace Dynamo { * @param scalar * @return Vec3& */ - inline Vec3 &operator*=(f32 scalar) { + inline Vec3 &operator*=(float scalar) { x *= scalar; y *= scalar; z *= scalar; @@ -130,8 +130,8 @@ namespace Dynamo { * @param scalar * @return Vec3& */ - inline Vec3 &operator/=(f32 scalar) { - f32 inv = 1.0f / scalar; + inline Vec3 &operator/=(float scalar) { + float inv = 1.0f / scalar; return *this *= inv; } @@ -150,7 +150,7 @@ namespace Dynamo { */ inline Vec3 &transform(const Mat4 &mat) { const auto &vals = mat.values; - f32 w = + float w = 1.0 / (vals[12] * x + vals[13] * y + vals[14] * z + vals[15]); x = (vals[0] * x + vals[1] * y + vals[2] * z + vals[3]) * w; y = (vals[4] * x + vals[5] * y + vals[6] * z + vals[7]) * w; @@ -162,9 +162,9 @@ namespace Dynamo { * @brief Dot product. * * @param rhs - * @return f32 + * @return float */ - inline f32 operator*(const Vec3 &rhs) const { + inline float operator*(const Vec3 &rhs) const { return x * rhs.x + y * rhs.y + z * rhs.z; } @@ -175,9 +175,9 @@ namespace Dynamo { * @return Vec3 */ inline Vec3 cross(const Vec3 &rhs) const { - f32 n_x = y * rhs.z - z * rhs.y; - f32 n_y = z * rhs.x - x * rhs.z; - f32 n_z = x * rhs.y - y * rhs.x; + float n_x = y * rhs.z - z * rhs.y; + float n_y = z * rhs.x - x * rhs.z; + float n_z = x * rhs.y - y * rhs.x; return Vec3(n_x, n_y, n_z); } @@ -188,7 +188,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 operator==(const Vec3 &rhs) const { + inline bool operator==(const Vec3 &rhs) const { return x == rhs.x && y == rhs.y && z == rhs.z; } @@ -199,7 +199,9 @@ namespace Dynamo { * @return true * @return false */ - inline b8 operator!=(const Vec3 &rhs) const { return !(*this == rhs); } + inline bool operator!=(const Vec3 &rhs) const { + return !(*this == rhs); + } }; } // namespace Dynamo @@ -211,9 +213,9 @@ namespace Dynamo { template <> struct std::hash { inline size_t operator()(const Dynamo::Vec3 &point) const { - Dynamo::i64 tx = point.x * 73856093; - Dynamo::i64 ty = point.y * 19349663; - Dynamo::i64 tz = point.z * 83492791; + long long tx = point.x * 73856093; + long long ty = point.y * 19349663; + long long tz = point.z * 83492791; return tx ^ ty ^ tz; } }; \ No newline at end of file diff --git a/src/Sound/Chunk.hpp b/src/Sound/Chunk.hpp index 56a32c43..3d38ee37 100644 --- a/src/Sound/Chunk.hpp +++ b/src/Sound/Chunk.hpp @@ -1,6 +1,5 @@ #pragma once -#include "../Types.hpp" #include "./Material.hpp" #include "./Sound.hpp" @@ -15,7 +14,7 @@ namespace Dynamo::Sound { * to receive enough data when requested, causing glitches. * */ - static constexpr u32 MAX_CHUNK_LENGTH = 1 << 9; + static constexpr unsigned MAX_CHUNK_LENGTH = 1 << 9; /** * @brief A chunk contains information to process a sound in small sections @@ -43,6 +42,6 @@ namespace Dynamo::Sound { * @brief Frame offset of the chunk. * */ - f32 frame; + float frame; }; } // namespace Dynamo::Sound \ No newline at end of file diff --git a/src/Sound/Convolver.cpp b/src/Sound/Convolver.cpp index 08f4bbae..abc6b151 100644 --- a/src/Sound/Convolver.cpp +++ b/src/Sound/Convolver.cpp @@ -1,18 +1,19 @@ #include "./Convolver.hpp" +#include "../Math/Fourier.hpp" namespace Dynamo::Sound { - void Convolver::initialize(WaveSample *ir, u32 M) { + void Convolver::initialize(WaveSample *ir, unsigned M) { // Initialize the partition buffer - _partition_count = std::ceil(static_cast(M) / BLOCK_LENGTH); + _partition_count = std::ceil(static_cast(M) / BLOCK_LENGTH); _partitions.resize(_partition_count * PARTITION_LENGTH); std::fill(_partitions.begin(), _partitions.end(), 0); // Copy impulse response and pre-compute the FFT of each partition - for (u32 i = 0; i < _partition_count; i++) { - u32 ir_offset = i * BLOCK_LENGTH; - u32 partition_offset = i * PARTITION_LENGTH; + for (unsigned i = 0; i < _partition_count; i++) { + unsigned ir_offset = i * BLOCK_LENGTH; + unsigned partition_offset = i * PARTITION_LENGTH; - u32 copy_size = std::min(BLOCK_LENGTH, M); + unsigned copy_size = std::min(BLOCK_LENGTH, M); std::copy(ir + ir_offset, ir + ir_offset + copy_size, _partitions.data() + partition_offset); @@ -26,22 +27,22 @@ namespace Dynamo::Sound { _fdl.resize(_partition_count * PARTITION_LENGTH); } - void Convolver::compute(WaveSample *src, WaveSample *dst, u32 N) { + void Convolver::compute(WaveSample *src, WaveSample *dst, unsigned N) { // Shift back the second half of the input buffer - for (u32 i = 0; i < BLOCK_LENGTH; i++) { + for (unsigned i = 0; i < BLOCK_LENGTH; i++) { _input[i] = _input[i + BLOCK_LENGTH]; } // Read the latest samples, zeroing out the remainder of buffer - for (u32 i = 0; i < N; i++) { + for (unsigned i = 0; i < N; i++) { _input[i + BLOCK_LENGTH] = src[i]; } - for (u32 i = N; i < BLOCK_LENGTH; i++) { + for (unsigned i = N; i < BLOCK_LENGTH; i++) { _input[i + BLOCK_LENGTH] = 0; } // Shift up the frequency delay-line by one partition - for (u32 i = _fdl.size() - 1; i >= PARTITION_LENGTH; i--) { + for (unsigned i = _fdl.size() - 1; i >= PARTITION_LENGTH; i--) { _fdl[i] = _fdl[i - PARTITION_LENGTH]; } @@ -51,12 +52,12 @@ namespace Dynamo::Sound { // Convolve with each partition std::fill(_output.begin(), _output.end(), 0); - for (u32 i = 0; i < _partition_count; i++) { - u32 offset = PARTITION_LENGTH * i; + for (unsigned i = 0; i < _partition_count; i++) { + unsigned offset = PARTITION_LENGTH * i; // Pointwise multiply and accumulate onto the output buffer - for (u32 j = 0; j < PARTITION_LENGTH; j++) { - u32 j_offset = offset + j; + for (unsigned j = 0; j < PARTITION_LENGTH; j++) { + unsigned j_offset = offset + j; _output[j] += _fdl[j_offset] * _partitions[j_offset]; } } @@ -65,7 +66,7 @@ namespace Dynamo::Sound { Fourier::inverse(_output.begin(), _output.size()); // Write the second half of the output buffer - for (u32 i = 0; i < N; i++) { + for (unsigned i = 0; i < N; i++) { dst[i] = _output[i + BLOCK_LENGTH].re; } } diff --git a/src/Sound/Convolver.hpp b/src/Sound/Convolver.hpp index 2a924fa3..b8b56509 100644 --- a/src/Sound/Convolver.hpp +++ b/src/Sound/Convolver.hpp @@ -4,10 +4,7 @@ #include #include "../Math/Complex.hpp" -#include "../Math/Fourier.hpp" -#include "../Types.hpp" #include "../Utils/Bits.hpp" -#include "../Utils/ChannelData.hpp" #include "./Chunk.hpp" #include "./Sound.hpp" @@ -17,14 +14,14 @@ namespace Dynamo::Sound { * @brief Length of a subfilter unit for convolutional processing * */ - static constexpr u32 BLOCK_LENGTH = round_pow2(MAX_CHUNK_LENGTH); + static constexpr unsigned BLOCK_LENGTH = round_pow2(MAX_CHUNK_LENGTH); /** * @brief Length of a partition unit on which FFT is performed for * convolutional processing * */ - static constexpr u32 PARTITION_LENGTH = BLOCK_LENGTH * 2; + static constexpr unsigned PARTITION_LENGTH = BLOCK_LENGTH * 2; /** * @brief Signal convolution engine @@ -62,7 +59,7 @@ namespace Dynamo::Sound { * @brief Number of partitions * */ - u32 _partition_count; + unsigned _partition_count; public: /** @@ -71,7 +68,7 @@ namespace Dynamo::Sound { * @param ir Impulse response buffer * @param M Length of the impulse response */ - void initialize(WaveSample *ir, u32 M); + void initialize(WaveSample *ir, unsigned M); /** * @brief Apply the impulse repsonse to a sound chunk @@ -80,6 +77,6 @@ namespace Dynamo::Sound { * @param dst Destination sound buffer * @param N Length of the sound, must be <= MAX_CHUNK_LENGTH */ - void compute(WaveSample *src, WaveSample *dst, u32 N); + void compute(WaveSample *src, WaveSample *dst, unsigned N); }; } // namespace Dynamo::Sound \ No newline at end of file diff --git a/src/Sound/Data/HRIR.hpp b/src/Sound/Data/HRIR.hpp index d5cd29d7..9303ffcf 100644 --- a/src/Sound/Data/HRIR.hpp +++ b/src/Sound/Data/HRIR.hpp @@ -1,8 +1,6 @@ #pragma once -#include "../../Types.hpp" - -static constexpr Dynamo::u8 HRIR_bin[] = { +static constexpr unsigned char HRIR_bin[] = { 0x04, 0x9b, 0x13, 0x33, 0x5d, 0x93, 0xf5, 0x33, 0xdd, 0xae, 0x67, 0xb6, 0x6f, 0x82, 0xf5, 0xb7, 0x09, 0x89, 0x86, 0xb8, 0xdb, 0x05, 0x6e, 0xb9, 0xfb, 0xe3, 0x27, 0xba, 0x73, 0x89, 0x3c, 0xba, 0xd5, 0xfa, 0x7d, 0xba, @@ -187204,4 +187202,4 @@ static constexpr Dynamo::u8 HRIR_bin[] = { 0xd6, 0x47, 0xe0, 0xb9, 0x24, 0xe5, 0x06, 0xba, 0x26, 0x27, 0x25, 0xb9, 0x98, 0x9e, 0x3c, 0xb8, 0xd2, 0xf7, 0xbf, 0xb8, 0xc0, 0x03, 0xbc, 0xb7 }; -static constexpr Dynamo::u32 HRIR_bin_len = 2246400; +static constexpr unsigned HRIR_bin_len = 2246400; diff --git a/src/Sound/Device.hpp b/src/Sound/Device.hpp index a5ef2d2b..7e904df4 100644 --- a/src/Sound/Device.hpp +++ b/src/Sound/Device.hpp @@ -2,8 +2,6 @@ #include -#include "../Types.hpp" - namespace Dynamo::Sound { /** * @brief Audio physical device. @@ -14,7 +12,7 @@ namespace Dynamo::Sound { * @brief Unique identifier of the device. * */ - i32 id; + int id; /** * @brief Name of the device. @@ -26,30 +24,30 @@ namespace Dynamo::Sound { * @brief Number of available input channels. * */ - u32 input_channels; + unsigned input_channels; /** * @brief Number of available output channels. * */ - u32 output_channels; + unsigned output_channels; /** * @brief Compatible sample rate. * */ - f32 sample_rate; + float sample_rate; /** * @brief Input latency. * */ - f32 input_latency; + float input_latency; /** * @brief Output latency. * */ - f32 output_latency; + float output_latency; }; } // namespace Dynamo::Sound \ No newline at end of file diff --git a/src/Sound/Filters/Attenuation.cpp b/src/Sound/Filters/Attenuation.cpp index 322848b7..052bb191 100644 --- a/src/Sound/Filters/Attenuation.cpp +++ b/src/Sound/Filters/Attenuation.cpp @@ -1,10 +1,10 @@ #include "./Attenuation.hpp" namespace Dynamo::Sound { - Attenuation::Attenuation(f32 inner_radius, f32 cutoff_radius) : + Attenuation::Attenuation(float inner_radius, float cutoff_radius) : _inner_radius(inner_radius), _cutoff_radius(cutoff_radius) {} - f32 Attenuation::linear(f32 distance) { + float Attenuation::linear(float distance) { if (distance < _inner_radius) { return 1; } @@ -15,16 +15,16 @@ namespace Dynamo::Sound { } Sound &Attenuation::apply(Sound &src, - const u32 src_offset, - const u32 length, + const unsigned src_offset, + const unsigned length, const DynamicMaterial &material, const ListenerProperties &listener) { _output.resize(length, src.channels()); - f32 distance = (material.position - listener.position).length(); - f32 gain = linear(distance); + float distance = (material.position - listener.position).length(); + float gain = linear(distance); - for (u32 c = 0; c < _output.channels(); c++) { - for (u32 f = 0; f < _output.frames(); f++) { + for (unsigned c = 0; c < _output.channels(); c++) { + for (unsigned f = 0; f < _output.frames(); f++) { _output[c][f] = src[c][f + src_offset] * gain; } } diff --git a/src/Sound/Filters/Attenuation.hpp b/src/Sound/Filters/Attenuation.hpp index 92e6a7fb..bd87ac86 100644 --- a/src/Sound/Filters/Attenuation.hpp +++ b/src/Sound/Filters/Attenuation.hpp @@ -1,6 +1,5 @@ #pragma once -#include "../../Types.hpp" #include "./Filter.hpp" namespace Dynamo::Sound { @@ -20,21 +19,21 @@ namespace Dynamo::Sound { * @brief Minimum distance to attenuate * */ - f32 _inner_radius; + float _inner_radius; /** * @brief Maximum distance to attenuate where the audio is cutoff * */ - f32 _cutoff_radius; + float _cutoff_radius; /** * @brief Linear attenuation function * * @param distance - * @return f32 + * @return float */ - f32 linear(f32 distance); + float linear(float distance); public: /** @@ -43,11 +42,11 @@ namespace Dynamo::Sound { * @param inner_radius Minimum distance to start attenuation * @param cutoff_radius Maximum distance to cutoff the sound */ - Attenuation(f32 inner_radius, f32 cutoff_radius); + Attenuation(float inner_radius, float cutoff_radius); Sound &apply(Sound &src, - const u32 src_offset, - const u32 length, + const unsigned src_offset, + const unsigned length, const DynamicMaterial &material, const ListenerProperties &listener) override; }; diff --git a/src/Sound/Filters/Binaural.cpp b/src/Sound/Filters/Binaural.cpp index c1c67aaf..a57ab143 100644 --- a/src/Sound/Filters/Binaural.cpp +++ b/src/Sound/Filters/Binaural.cpp @@ -7,8 +7,8 @@ namespace Dynamo::Sound { } Sound &Binaural::apply(Sound &src, - const u32 src_offset, - const u32 length, + const unsigned src_offset, + const unsigned length, const DynamicMaterial &material, const ListenerProperties &listener) { _output.set_frames(length); @@ -16,7 +16,7 @@ namespace Dynamo::Sound { listener.rotation, material.position, _impulse_response); - for (i32 c = 0; c < 2; c++) { + for (unsigned c = 0; c < 2; c++) { _convolvers[c].initialize(_impulse_response[c], _impulse_response.frames()); _convolvers[c].compute(src[c] + src_offset, _output[c], length); diff --git a/src/Sound/Filters/Binaural.hpp b/src/Sound/Filters/Binaural.hpp index c579d765..e551ed64 100644 --- a/src/Sound/Filters/Binaural.hpp +++ b/src/Sound/Filters/Binaural.hpp @@ -2,7 +2,6 @@ #include -#include "../../Types.hpp" #include "../Convolver.hpp" #include "../HRTF.hpp" #include "./Filter.hpp" @@ -28,8 +27,8 @@ namespace Dynamo::Sound { Binaural(HRTF &hrtf); Sound &apply(Sound &src, - const u32 src_offset, - const u32 length, + const unsigned src_offset, + const unsigned length, const DynamicMaterial &material, const ListenerProperties &listener) override; }; diff --git a/src/Sound/Filters/Filter.hpp b/src/Sound/Filters/Filter.hpp index 87f92483..0293d44e 100644 --- a/src/Sound/Filters/Filter.hpp +++ b/src/Sound/Filters/Filter.hpp @@ -1,9 +1,5 @@ #pragma once -#include "../../Math/Quaternion.hpp" -#include "../../Math/Vec3.hpp" -#include "../../Types.hpp" - #include "../Listener.hpp" #include "../Material.hpp" #include "../Sound.hpp" @@ -26,7 +22,7 @@ namespace Dynamo::Sound { * @return Sound& */ virtual Sound & - apply(Sound &src, const u32 src_offset, const u32 length) = 0; + apply(Sound &src, const unsigned src_offset, const unsigned length) = 0; }; /** @@ -49,8 +45,8 @@ namespace Dynamo::Sound { * @return Sound& */ virtual Sound &apply(Sound &src, - const u32 src_offset, - const u32 length, + const unsigned src_offset, + const unsigned length, const DynamicMaterial &material, const ListenerProperties &listener) = 0; }; diff --git a/src/Sound/Filters/Stereo.cpp b/src/Sound/Filters/Stereo.cpp index efe16746..27f09fd9 100644 --- a/src/Sound/Filters/Stereo.cpp +++ b/src/Sound/Filters/Stereo.cpp @@ -4,31 +4,31 @@ namespace Dynamo::Sound { Stereo::Stereo() { _output.set_channels(2); } Sound &Stereo::apply(Sound &src, - const u32 src_offset, - const u32 length, + const unsigned src_offset, + const unsigned length, const DynamicMaterial &material, const ListenerProperties &listener) { Vec3 delta = material.position - listener.position; Vec3 up = listener.rotation.up(); Vec3 right = listener.rotation.right(); Vec3 displacement = (delta - up * (delta * up)); - f32 distance = displacement.length(); + float distance = displacement.length(); // Assume that if the distance is 0, the sound is centered - f32 pan = 0.5; + float pan = 0.5; if (distance > 0) { Vec3 direction = displacement / distance; pan = ((direction * right) + 1) * 0.5; } // Square-law panning - f32 l_gain = std::sqrt(1 - pan); - f32 r_gain = std::sqrt(pan); + float l_gain = std::sqrt(1 - pan); + float r_gain = std::sqrt(pan); _output.set_frames(length); - for (u32 c = 0; c < 2; c++) { - f32 gain = c == 0 ? l_gain : r_gain; - for (u32 f = 0; f < length; f++) { + for (unsigned c = 0; c < 2; c++) { + float gain = c == 0 ? l_gain : r_gain; + for (unsigned f = 0; f < length; f++) { _output[c][f] = src[c][f + src_offset] * gain; } } diff --git a/src/Sound/Filters/Stereo.hpp b/src/Sound/Filters/Stereo.hpp index f74f237b..d51711e8 100644 --- a/src/Sound/Filters/Stereo.hpp +++ b/src/Sound/Filters/Stereo.hpp @@ -1,6 +1,5 @@ #pragma once -#include "../../Types.hpp" #include "./Filter.hpp" namespace Dynamo::Sound { @@ -23,8 +22,8 @@ namespace Dynamo::Sound { Stereo(); Sound &apply(Sound &src, - const u32 src_offset, - const u32 length, + const unsigned src_offset, + const unsigned length, const DynamicMaterial &material, const ListenerProperties &listener) override; }; diff --git a/src/Sound/HRTF.cpp b/src/Sound/HRTF.cpp index 3c3a6501..cbe71206 100644 --- a/src/Sound/HRTF.cpp +++ b/src/Sound/HRTF.cpp @@ -1,20 +1,23 @@ #include "HRTF.hpp" +#include "../Math/Common.hpp" +#include "../Math/Delaunay.hpp" +#include "../Math/Triangle2.hpp" namespace Dynamo::Sound { HRTF::HRTF() { // Generate point space - for (const f32 &a : HRTF_AZIMUTHS) { + for (const float &a : HRTF_AZIMUTHS) { _points.push_back({a, -90}); - for (u32 i = 0; i < 50; i++) { - f32 e = -45 + 5.625 * i; + for (unsigned i = 0; i < 50; i++) { + float e = -45 + 5.625 * i; _points.push_back({a, e}); } _points.push_back({a, 270}); } // Map each point to its index - std::unordered_map index_map; - for (u32 i = 0; i < _points.size(); i++) { + std::unordered_map index_map; + for (unsigned i = 0; i < _points.size(); i++) { index_map[_points[i]] = i; } @@ -27,11 +30,11 @@ namespace Dynamo::Sound { } // Read the HRIR samples for each point - u32 offset = 0; - for (u32 i = 0; i < _points.size(); i++) { + unsigned offset = 0; + for (unsigned i = 0; i < _points.size(); i++) { _coeff_map[i].resize(HRIR_LENGTH, 2); - for (u32 c = 0; c < 2; c++) { - for (u32 f = 0; f < HRIR_LENGTH; f++) { + for (unsigned c = 0; c < 2; c++) { + for (unsigned f = 0; f < HRIR_LENGTH; f++) { _coeff_map[i][c][f] = HRIR_COEFFICIENTS[offset++]; } } @@ -42,8 +45,8 @@ namespace Dynamo::Sound { const Vec3 &source_position) { Vec3 disp = source_position - listener_position; - f32 azimuth = std::asin(disp.x / disp.length()); - f32 elevation = std::atan2(-disp.z, disp.y); + float azimuth = std::asin(disp.x / disp.length()); + float elevation = std::atan2(-disp.z, disp.y); if (disp.y < 0 && disp.z < 0) { elevation += 2 * M_PI; } @@ -57,10 +60,10 @@ namespace Dynamo::Sound { Sound &dst_buffer) { dst_buffer.clear(); Vec2 point = compute_point(listener_position, source_position); - for (u32 t = 0; t < _indices.size() / 3; t++) { - u32 a = _indices[t * 3]; - u32 b = _indices[t * 3 + 1]; - u32 c = _indices[t * 3 + 2]; + for (unsigned t = 0; t < _indices.size() / 3; t++) { + unsigned a = _indices[t * 3]; + unsigned b = _indices[t * 3 + 1]; + unsigned c = _indices[t * 3 + 2]; Triangle2 triangle(_points[a], _points[b], _points[c]); Vec3 coords = triangle.barycentric(point); @@ -70,8 +73,8 @@ namespace Dynamo::Sound { Sound &ir2 = _coeff_map[c]; // Use barycentric coordinates to interpolate samples - for (u32 c = 0; c < dst_buffer.channels(); c++) { - for (u32 f = 0; f < dst_buffer.frames(); f++) { + for (unsigned c = 0; c < dst_buffer.channels(); c++) { + for (unsigned f = 0; f < dst_buffer.frames(); f++) { dst_buffer[c][f] = ir0[c][f] * coords.x + ir1[c][f] * coords.y + ir2[c][f] * coords.z; diff --git a/src/Sound/HRTF.hpp b/src/Sound/HRTF.hpp index 09cd19ff..171f1032 100644 --- a/src/Sound/HRTF.hpp +++ b/src/Sound/HRTF.hpp @@ -1,22 +1,12 @@ #pragma once -#include -#include #include -#include #include -#include "../Math/Common.hpp" -#include "../Math/Complex.hpp" -#include "../Math/Delaunay.hpp" #include "../Math/Quaternion.hpp" -#include "../Math/Triangle2.hpp" #include "../Math/Vec2.hpp" #include "../Math/Vec3.hpp" -#include "../Types.hpp" -#include "../Utils/ChannelData.hpp" -#include "./Convolver.hpp" #include "./Data/HRIR.hpp" #include "./Sound.hpp" @@ -27,7 +17,7 @@ namespace Dynamo::Sound { * @return WaveForm */ static WaveForm read_HRIR_coefficients() { - WaveForm buffer(HRIR_bin_len / sizeof(f32)); + WaveForm buffer(HRIR_bin_len / sizeof(float)); std::memcpy(buffer.data(), HRIR_bin, HRIR_bin_len); return buffer; } @@ -42,13 +32,13 @@ namespace Dynamo::Sound { * @brief Length of an HRIR * */ - static constexpr u32 HRIR_LENGTH = 200; + static constexpr unsigned HRIR_LENGTH = 200; /** * @brief HRTF point space x-coordinates * */ - static constexpr std::array HRTF_AZIMUTHS = { + static constexpr std::array HRTF_AZIMUTHS = { -90, -80, -65, -55, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 55, 65, 80, 90, }; @@ -60,9 +50,9 @@ namespace Dynamo::Sound { */ class HRTF { std::vector _points; - std::vector _indices; + std::vector _indices; - std::unordered_map _coeff_map; + std::unordered_map _coeff_map; /** * @brief Compute the azimuth and elevation angles diff --git a/src/Sound/Jukebox.cpp b/src/Sound/Jukebox.cpp index cb7b5c12..3e7f6096 100644 --- a/src/Sound/Jukebox.cpp +++ b/src/Sound/Jukebox.cpp @@ -1,4 +1,6 @@ #include "Jukebox.hpp" +#include "./Filters/Filter.hpp" +#include "Resample.hpp" #include "portaudio.h" namespace Dynamo::Sound { @@ -68,7 +70,7 @@ namespace Dynamo::Sound { } } - i32 Jukebox::input_callback(const void *input, + int Jukebox::input_callback(const void *input, void *output, unsigned long frame_count, const PaStreamCallbackTimeInfo *time_info, @@ -80,7 +82,7 @@ namespace Dynamo::Sound { return 0; } - i32 Jukebox::output_callback(const void *input, + int Jukebox::output_callback(const void *input, void *output, unsigned long frame_count, const PaStreamCallbackTimeInfo *time_info, @@ -97,18 +99,18 @@ namespace Dynamo::Sound { StaticMaterial &material = chunk.material.get(); // Calculate the number of frames in the destination - f64 frame_stop = std::min(chunk.frame + MAX_CHUNK_LENGTH, - static_cast(sound.frames())); - f64 frames = frame_stop - chunk.frame; + double frame_stop = std::min(chunk.frame + MAX_CHUNK_LENGTH, + static_cast(sound.frames())); + double frames = frame_stop - chunk.frame; // Calculate the number of frames required in the original signal to // produce the destination frames - f64 factor = sound.sample_rate() / _output_state.sample_rate; - f64 length = frames * factor; + double factor = sound.sample_rate() / _output_state.sample_rate; + double length = frames * factor; // Resample the audio to the device sample rate Sound transformed(frames, _output_state.channels); - for (u32 c = 0; c < transformed.channels(); c++) { + for (unsigned c = 0; c < transformed.channels(); c++) { resample_signal(sound[c], transformed[c], chunk.frame, @@ -123,12 +125,12 @@ namespace Dynamo::Sound { } // Mix the filtered sound onto the composite signal - f32 volume = material.volume * _volume; - for (u32 f = 0; f < transformed.frames(); f++) { - for (u32 c = 0; c < transformed.channels(); c++) { - u32 i = f * transformed.channels() + c; - f32 s0 = _composite[i]; - f32 s1 = transformed[c][f]; + float volume = material.volume * _volume; + for (unsigned f = 0; f < transformed.frames(); f++) { + for (unsigned c = 0; c < transformed.channels(); c++) { + unsigned i = f * transformed.channels() + c; + float s0 = _composite[i]; + float s1 = transformed[c][f]; _composite[i] = (s0 + s1) * volume; } } @@ -144,18 +146,18 @@ namespace Dynamo::Sound { DynamicMaterial &material = chunk.material.get(); // Calculate the number of frames in the destination - f64 frame_stop = std::min(chunk.frame + MAX_CHUNK_LENGTH, - static_cast(sound.frames())); - f64 frames = frame_stop - chunk.frame; + double frame_stop = std::min(chunk.frame + MAX_CHUNK_LENGTH, + static_cast(sound.frames())); + double frames = frame_stop - chunk.frame; // Calculate the number of frames required in the original signal to // produce the destination frames - f64 factor = sound.sample_rate() / _output_state.sample_rate; - f64 length = frames * factor; + double factor = sound.sample_rate() / _output_state.sample_rate; + double length = frames * factor; // Resample the audio to the device sample rate Sound transformed(frames, _output_state.channels); - for (u32 c = 0; c < transformed.channels(); c++) { + for (unsigned c = 0; c < transformed.channels(); c++) { resample_signal(sound[c], transformed[c], chunk.frame, @@ -176,12 +178,12 @@ namespace Dynamo::Sound { } // Mix the filtered sound onto the composite signal - f32 volume = material.volume * listener.volume * _volume; - for (u32 f = 0; f < transformed.frames(); f++) { - for (u32 c = 0; c < transformed.channels(); c++) { - u32 i = f * transformed.channels() + c; - f32 s0 = _composite[i]; - f32 s1 = transformed[c][f]; + float volume = material.volume * listener.volume * _volume; + for (unsigned f = 0; f < transformed.frames(); f++) { + for (unsigned c = 0; c < transformed.channels(); c++) { + unsigned i = f * transformed.channels() + c; + float s0 = _composite[i]; + float s1 = transformed[c][f]; _composite[i] = (s0 + s1) * volume; } } @@ -195,7 +197,7 @@ namespace Dynamo::Sound { PaError err; // Count the devices - i32 device_count = Pa_GetDeviceCount(); + int device_count = Pa_GetDeviceCount(); if (device_count < 0) { err = device_count; Log::error("PortAudio failed to count sound devices: {}", @@ -203,7 +205,7 @@ namespace Dynamo::Sound { } // List all devices - for (i32 index = 0; index < device_count; index++) { + for (int index = 0; index < device_count; index++) { const PaDeviceInfo *device_info = Pa_GetDeviceInfo(index); Device device; device.id = index; @@ -317,21 +319,21 @@ namespace Dynamo::Sound { _composite.resize(MAX_CHUNK_LENGTH * device.output_channels, 0); } - b8 Jukebox::is_playing() { + bool Jukebox::is_playing() { return _output_stream != nullptr && Pa_IsStreamActive(_output_stream); } - b8 Jukebox::is_recording() { + bool Jukebox::is_recording() { return _input_stream != nullptr && Pa_IsStreamActive(_input_stream); } - f32 Jukebox::get_volume() { return _volume; } + float Jukebox::get_volume() { return _volume; } void Jukebox::pause() { Pa_StopStream(_output_stream); } void Jukebox::resume() { Pa_StartStream(_output_stream); } - void Jukebox::set_volume(f32 volume) { + void Jukebox::set_volume(float volume) { _volume = std::clamp(volume, 0.0f, 1.0f); } @@ -340,18 +342,18 @@ namespace Dynamo::Sound { HRTF &Jukebox::get_hrtf() { return _hrtf; } void Jukebox::play(Sound &sound, StaticMaterial &material) { - f32 frame = _output_state.sample_rate * material.start_seconds; + float frame = _output_state.sample_rate * material.start_seconds; _static_chunks.push_back({sound, material, frame}); } void Jukebox::play(Sound &sound, DynamicMaterial &material) { - f32 frame = _output_state.sample_rate * material.start_seconds; + float frame = _output_state.sample_rate * material.start_seconds; _dynamic_chunks.push_back({sound, material, frame}); } void Jukebox::update() { // Wait for there to be available space in the buffer - u32 min_length = MAX_CHUNK_LENGTH * _output_state.channels; + unsigned min_length = MAX_CHUNK_LENGTH * _output_state.channels; if (_output_state.buffer.remaining() < min_length || !is_playing()) { return; } diff --git a/src/Sound/Jukebox.hpp b/src/Sound/Jukebox.hpp index dc785a6a..93649982 100644 --- a/src/Sound/Jukebox.hpp +++ b/src/Sound/Jukebox.hpp @@ -1,27 +1,17 @@ #pragma once -#include -#include -#include #include #include -#include "../Log/Log.hpp" -#include "../Math/Vec3.hpp" -#include "../Types.hpp" #include "../Utils/IdTracker.hpp" #include "../Utils/RingBuffer.hpp" -#include "../Utils/SparseSet.hpp" #include "./Chunk.hpp" #include "./Device.hpp" -#include "./Filters/Binaural.hpp" -#include "./Filters/Filter.hpp" #include "./HRTF.hpp" #include "./Listener.hpp" #include "./Material.hpp" -#include "./Resample.hpp" #include "./Sound.hpp" namespace Dynamo::Sound { @@ -29,7 +19,7 @@ namespace Dynamo::Sound { * @brief Size of the input and output ring buffers * */ - static constexpr u32 BUFFER_SIZE = MAX_CHUNK_LENGTH * 64; + static constexpr unsigned BUFFER_SIZE = MAX_CHUNK_LENGTH * 64; /** * @brief A playback track on which audio can be enqueued @@ -52,7 +42,7 @@ namespace Dynamo::Sound { * @brief Global volume control * */ - f32 _volume; + float _volume; /** * @brief Final waveform on which all active chunks are layered onto @@ -99,13 +89,13 @@ namespace Dynamo::Sound { * @brief Number of channels in the buffer * */ - u32 channels; + unsigned channels; /** * @brief Sampling rate of the buffer * */ - f64 sample_rate; + double sample_rate; }; State _input_state; State _output_state; @@ -119,9 +109,9 @@ namespace Dynamo::Sound { * @param time_info Time information in seconds * @param status_flags Status flags * @param data User data - * @return i32 + * @return int */ - static i32 input_callback(const void *input, + static int input_callback(const void *input, void *output, unsigned long frame_count, const PaStreamCallbackTimeInfo *time_info, @@ -137,9 +127,9 @@ namespace Dynamo::Sound { * @param time_info Time information in seconds * @param status_flags Status flags * @param data User data - * @return i32 + * @return int */ - static i32 output_callback(const void *input, + static int output_callback(const void *input, void *output, unsigned long frame_count, const PaStreamCallbackTimeInfo *time_info, @@ -201,16 +191,16 @@ namespace Dynamo::Sound { /** * @brief Get the sample rate of the input stream * - * @return u32 + * @return unsigned */ - u32 get_input_sample_rate(); + unsigned get_input_sample_rate(); /** * @brief Get the sample rate of the output stream * - * @return u32 + * @return unsigned */ - u32 get_output_sample_rate(); + unsigned get_output_sample_rate(); /** * @brief Is the output device playing? @@ -218,7 +208,7 @@ namespace Dynamo::Sound { * @return true * @return false */ - b8 is_playing(); + bool is_playing(); /** * @brief Is the input device listening @@ -226,14 +216,14 @@ namespace Dynamo::Sound { * @return true * @return false */ - b8 is_recording(); + bool is_recording(); /** * @brief Get the master volume * - * @return f32 + * @return float */ - f32 get_volume(); + float get_volume(); /** * @brief Pause audio playback @@ -252,7 +242,7 @@ namespace Dynamo::Sound { * * @param volume */ - void set_volume(f32 volume); + void set_volume(float volume); /** * @brief Get the set of listeners diff --git a/src/Sound/Listener.hpp b/src/Sound/Listener.hpp index 10dafbde..d2325044 100644 --- a/src/Sound/Listener.hpp +++ b/src/Sound/Listener.hpp @@ -2,7 +2,6 @@ #include "../Math/Quaternion.hpp" #include "../Math/Vec3.hpp" -#include "../Types.hpp" #include "../Utils/IdTracker.hpp" #include "../Utils/SparseSet.hpp" @@ -22,7 +21,7 @@ namespace Dynamo::Sound { * @brief Listener volume * */ - f32 volume = 1.0; + float volume = 1.0; /** * @brief Position of the listener in 3D space @@ -64,9 +63,9 @@ namespace Dynamo::Sound { /** * @brief Get the number of listeners * - * @return u32 + * @return unsigned */ - inline u32 size() { return _properties.size(); } + inline unsigned size() { return _properties.size(); } /** * @brief Create a new listener @@ -122,7 +121,7 @@ namespace Dynamo::Sound { * @param index * @return ListenerProperties& */ - inline ListenerProperties &operator[](u32 index) { + inline ListenerProperties &operator[](unsigned index) { return _properties.at(index); } @@ -133,13 +132,13 @@ namespace Dynamo::Sound { * @return ListenerProperties& */ ListenerProperties &find_closest(Vec3 position) { - u32 closest_index = 0; - for (u32 i = 0; i < _properties.size(); i++) { + unsigned closest_index = 0; + for (unsigned i = 0; i < _properties.size(); i++) { Vec3 best = _properties.at(i).position; Vec3 curr = _properties.at(closest_index).position; - f32 a = (best - position).length_squared(); - f32 b = (curr - position).length_squared(); + float a = (best - position).length_squared(); + float b = (curr - position).length_squared(); if (b < a) { closest_index = i; } diff --git a/src/Sound/Material.hpp b/src/Sound/Material.hpp index cba7ce17..01eeec76 100644 --- a/src/Sound/Material.hpp +++ b/src/Sound/Material.hpp @@ -3,8 +3,6 @@ #include #include "../Math/Vec3.hpp" -#include "../Types.hpp" -#include "./Sound.hpp" namespace Dynamo::Sound { /** @@ -24,13 +22,13 @@ namespace Dynamo::Sound { * @brief Volume to be played relative to overall gain * */ - f32 volume = 1.0; + float volume = 1.0; /** * @brief Start time in seconds * */ - f32 start_seconds = 0.0; + float start_seconds = 0.0; /** * @brief Filter pipeline @@ -48,13 +46,13 @@ namespace Dynamo::Sound { * @brief Volume to be played relative to overall gain * */ - f32 volume = 1.0; + float volume = 1.0; /** * @brief Start time in seconds * */ - f32 start_seconds = 0.0; + float start_seconds = 0.0; /** * @brief Position of the sound in 3D space diff --git a/src/Sound/Resample.cpp b/src/Sound/Resample.cpp index 053f877a..bad2147b 100644 --- a/src/Sound/Resample.cpp +++ b/src/Sound/Resample.cpp @@ -3,40 +3,40 @@ namespace Dynamo::Sound { void resample_signal(WaveSample *src, WaveSample *dst, - f64 time_offset, - f64 src_length, - f64 src_rate, - f64 dst_rate) { - f64 factor = dst_rate / src_rate; - f64 scale = std::min(1.0, factor); - f64 time_increment = 1.0 / factor; + double time_offset, + double src_length, + double src_rate, + double dst_rate) { + double factor = dst_rate / src_rate; + double scale = std::min(1.0, factor); + double time_increment = 1.0 / factor; - u32 dst_length = src_length * factor; - u32 filter_step = scale * FILTER_PRECISION; + unsigned dst_length = src_length * factor; + unsigned filter_step = scale * FILTER_PRECISION; - f64 time = time_offset; - f64 time_end = src_length + time_offset; + double time = time_offset; + double time_end = src_length + time_offset; - for (u32 dst_f = 0; dst_f < dst_length; dst_f++) { + for (unsigned dst_f = 0; dst_f < dst_length; dst_f++) { // Target sample - f64 dst_sample = 0; + double dst_sample = 0; // Get the source frame - u32 src_f = time; - f64 P = scale * (time - src_f); + unsigned src_f = time; + double P = scale * (time - src_f); // Calculate filter offset and interpolation factor - f64 P_frac = P * FILTER_PRECISION; - u32 l = P_frac; - f64 interp = P_frac - l; + double P_frac = P * FILTER_PRECISION; + unsigned l = P_frac; + double interp = P_frac - l; // Left wing - for (u32 i = 0; i < FILTER_HALF_LENGTH; i++) { - i32 s_i = src_f - i; - i32 h_i = l + i * filter_step; - if (s_i < 0 || h_i >= static_cast(FILTER_HALF_LENGTH)) + for (unsigned i = 0; i < FILTER_HALF_LENGTH; i++) { + int s_i = src_f - i; + int h_i = l + i * filter_step; + if (s_i < 0 || h_i >= static_cast(FILTER_HALF_LENGTH)) break; - f64 weight = FILTER_RWING[h_i] + interp * FILTER_DIFFS[h_i]; + double weight = FILTER_RWING[h_i] + interp * FILTER_DIFFS[h_i]; dst_sample += src[s_i] * weight; } @@ -49,13 +49,13 @@ namespace Dynamo::Sound { interp = P_frac - l; // Right wing - for (u32 i = 0; i < FILTER_HALF_LENGTH; i++) { - i32 s_i = src_f + i + 1; - i32 h_i = l + i * filter_step; + for (unsigned i = 0; i < FILTER_HALF_LENGTH; i++) { + int s_i = src_f + i + 1; + int h_i = l + i * filter_step; if (s_i >= time_end || - h_i >= static_cast(FILTER_HALF_LENGTH)) + h_i >= static_cast(FILTER_HALF_LENGTH)) break; - f64 weight = FILTER_RWING[h_i] + interp * FILTER_DIFFS[h_i]; + double weight = FILTER_RWING[h_i] + interp * FILTER_DIFFS[h_i]; dst_sample += src[s_i] * weight; } diff --git a/src/Sound/Resample.hpp b/src/Sound/Resample.hpp index a10f885f..498e4cb8 100644 --- a/src/Sound/Resample.hpp +++ b/src/Sound/Resample.hpp @@ -3,8 +3,6 @@ #include -#include "../Log/Log.hpp" -#include "../Types.hpp" #include "./Sound.hpp" namespace Dynamo::Sound { @@ -12,30 +10,30 @@ namespace Dynamo::Sound { * @brief Number of zero-crossings in the filter * */ - static constexpr u32 FILTER_ZERO_CROSSINGS = 32; + static constexpr unsigned FILTER_ZERO_CROSSINGS = 32; /** * @brief Number of coefficients per zero crossing * */ - static constexpr u32 FILTER_PRECISION = 4; + static constexpr unsigned FILTER_PRECISION = 4; /** * @brief Length of one wing in the filter * */ - static constexpr u32 FILTER_HALF_LENGTH = + static constexpr unsigned FILTER_HALF_LENGTH = FILTER_ZERO_CROSSINGS * FILTER_PRECISION + 1; /** * @brief Normalized sinc function * * @param x - * @return constexpr f64 + * @return constexpr double */ - constexpr f64 sinc(f64 x) { + constexpr double sinc(double x) { if (x == 0) return 1; - f64 f = M_PI * x; + double f = M_PI * x; return std::sin(f) / f; } @@ -43,13 +41,13 @@ namespace Dynamo::Sound { * @brief Compute the zeroth-order modified Bessel function * * @param x - * @return constexpr f64 + * @return constexpr double */ - constexpr f64 i0(f64 x) { - constexpr f64 epsilon = 0.00000001; - f64 sum = 1; - f64 term = 1; - f64 m = 0; + constexpr double i0(double x) { + constexpr double epsilon = 0.00000001; + double sum = 1; + double term = 1; + double m = 0; while (term > epsilon * sum) { sum += term; m++; @@ -62,24 +60,24 @@ namespace Dynamo::Sound { * @brief Compute the Kaiser window * * @param x - * @return constexpr f64 + * @return constexpr double */ - constexpr f64 filter_window(f64 n, u32 N = 35, f64 beta = 6) { - f64 m = 2.0 * n / N; - f64 num = i0(beta * std::sqrt(1 - m * m)); - f64 den = i0(beta); + constexpr double filter_window(double n, unsigned N = 35, double beta = 6) { + double m = 2.0 * n / N; + double num = i0(beta * std::sqrt(1 - m * m)); + double den = i0(beta); return num / den; } /** * @brief Compulte the right-wing of the filter coefficients * - * @return constexpr std::array + * @return constexpr std::array */ - constexpr std::array construct_filter_table() { - std::array coeffs = {0}; - for (f64 l = 0; l < FILTER_HALF_LENGTH; l++) { - f64 f = l / FILTER_PRECISION; + constexpr std::array construct_filter_table() { + std::array coeffs = {0}; + for (double l = 0; l < FILTER_HALF_LENGTH; l++) { + double f = l / FILTER_PRECISION; coeffs[l] = sinc(f) * filter_window(l); } return coeffs; @@ -89,12 +87,12 @@ namespace Dynamo::Sound { * @brief Compute the filter coefficient difference table * * @param coeffs - * @return constexpr std::array + * @return constexpr std::array */ - constexpr std::array construct_difference_table( - const std::array &coeffs) { - std::array diffs = {0}; - for (u32 i = 0; i < FILTER_HALF_LENGTH - 1; i++) { + constexpr std::array construct_difference_table( + const std::array &coeffs) { + std::array diffs = {0}; + for (unsigned i = 0; i < FILTER_HALF_LENGTH - 1; i++) { diffs[i] = coeffs[i + 1] - coeffs[i]; } return diffs; @@ -105,7 +103,7 @@ namespace Dynamo::Sound { * initialization * */ - static const std::array FILTER_RWING = + static const std::array FILTER_RWING = construct_filter_table(); /** @@ -113,7 +111,7 @@ namespace Dynamo::Sound { * initialization * */ - static const std::array FILTER_DIFFS = + static const std::array FILTER_DIFFS = construct_difference_table(FILTER_RWING); /** @@ -131,8 +129,8 @@ namespace Dynamo::Sound { */ void resample_signal(WaveSample *src, WaveSample *dst, - f64 time_offset, - f64 src_length, - f64 src_rate, - f64 dst_rate); + double time_offset, + double src_length, + double src_rate, + double dst_rate); } // namespace Dynamo::Sound \ No newline at end of file diff --git a/src/Sound/Sound.cpp b/src/Sound/Sound.cpp index 26a2a4a7..6bbc52e7 100644 --- a/src/Sound/Sound.cpp +++ b/src/Sound/Sound.cpp @@ -1,24 +1,36 @@ #include "Sound.hpp" namespace Dynamo::Sound { - WaveFrame Sound::get_frame(const u32 frame, const u32 out_channels) { + Sound::Sound(unsigned frames, unsigned channels, float sample_rate) : + ChannelData(frames, channels), _sample_rate(sample_rate) {} + + Sound::Sound(std::vector samples, + unsigned channels, + float sample_rate) : + ChannelData(samples, channels), + _sample_rate(sample_rate) {} + + float Sound::sample_rate() const { return _sample_rate; } + + WaveFrame Sound::get_frame(const unsigned frame, + const unsigned out_channels) { WaveFrame output; output.channels = out_channels; - std::array samples = {0, 0}; - for (u32 src_c = 0; src_c < channels(); src_c++) { + std::array samples = {0, 0}; + for (unsigned src_c = 0; src_c < channels(); src_c++) { WaveSample sample = at(frame, src_c); // Perform weighted sum using downmixing coefficient matrix - i32 index = static_cast(CHANNEL_ORDERS[channels() - 1][src_c]); - for (u32 dst_c = 0; dst_c < output.channels; dst_c++) { - f32 coeff = DOWNMIX_COEFFS[out_channels - 1][index][dst_c]; + int index = static_cast(CHANNEL_ORDERS[channels() - 1][src_c]); + for (unsigned dst_c = 0; dst_c < output.channels; dst_c++) { + float coeff = DOWNMIX_COEFFS[out_channels - 1][index][dst_c]; samples[dst_c] += sample * coeff; } } // Write denormalzed samples onto the output frame - for (u32 i = 0; i < samples.size(); i++) { + for (unsigned i = 0; i < samples.size(); i++) { output.samples[i] = samples[i]; } return output; diff --git a/src/Sound/Sound.hpp b/src/Sound/Sound.hpp index 66d5d3e5..bfb34ef8 100644 --- a/src/Sound/Sound.hpp +++ b/src/Sound/Sound.hpp @@ -1,13 +1,8 @@ #pragma once -#include #include -#include #include -#include "../Types.hpp" -#include "../Log/Log.hpp" -#include "../Math/Fourier.hpp" #include "../Utils/ChannelData.hpp" namespace Dynamo::Sound { @@ -15,7 +10,7 @@ namespace Dynamo::Sound { * @brief Indiviual sample ranges between [−1.0, +1.0] * */ - using WaveSample = f32; + using WaveSample = float; /** * @brief An array of samples, a discrete representation of a sound wave @@ -31,7 +26,7 @@ namespace Dynamo::Sound { */ struct WaveFrame { std::array samples; - u32 channels; + unsigned channels; }; /** @@ -87,7 +82,7 @@ namespace Dynamo::Sound { * @brief Gain coefficients for downmixing a waveform to mono or stereo * */ - static const f64 DOWNMIX_COEFFS[2][9][2] = { + static const double DOWNMIX_COEFFS[2][9][2] = { { {M_SQRT1_2}, {1}, @@ -116,7 +111,7 @@ namespace Dynamo::Sound { * @brief The default sample rate is defined to be 44.1KHz * */ - static constexpr f32 DEFAULT_SAMPLE_RATE = 44100; + static constexpr float DEFAULT_SAMPLE_RATE = 44100; /** * @brief Sound asset represented as a signal holding multiple channels of @@ -124,7 +119,7 @@ namespace Dynamo::Sound { * */ class Sound : public ChannelData { - f32 _sample_rate; + float _sample_rate; public: /** @@ -134,11 +129,9 @@ namespace Dynamo::Sound { * @param channels Number of channels * @param sample_rate Sample rate */ - Sound(u32 frames = 0, - u32 channels = 0, - f32 sample_rate = DEFAULT_SAMPLE_RATE) : - ChannelData(frames, channels), - _sample_rate(sample_rate) {} + Sound(unsigned frames = 0, + unsigned channels = 0, + float sample_rate = DEFAULT_SAMPLE_RATE); /** * @brief Construct a new Sound object from an existing buffer @@ -148,17 +141,15 @@ namespace Dynamo::Sound { * @param sample_rate Sample rate */ Sound(std::vector samples, - u32 channels, - f32 sample_rate) : - ChannelData(samples, channels), - _sample_rate(sample_rate) {} + unsigned channels, + float sample_rate); /** * @brief Get the sample rate of the signal * - * @return f32 + * @return float */ - inline f32 sample_rate() const { return _sample_rate; } + float sample_rate() const; /** * @brief Grab a frame in the waveform and upmix or downmix to the @@ -168,6 +159,6 @@ namespace Dynamo::Sound { * @param out_channels Target number of channels * @return WaveFrame */ - WaveFrame get_frame(const u32 frame, const u32 out_channels); + WaveFrame get_frame(const unsigned frame, const unsigned out_channels); }; } // namespace Dynamo::Sound \ No newline at end of file diff --git a/src/Types.hpp b/src/Types.hpp deleted file mode 100644 index e45ee65c..00000000 --- a/src/Types.hpp +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -namespace Dynamo { - /** - * @brief Standard boolean - * - */ - using b8 = bool; - - /** - * @brief 8-bit integer - * - */ - using i8 = char; - - /** - * @brief 16-bit integer - * - */ - using i16 = short; - - /** - * @brief 32-bit integer - * - */ - using i32 = int; - - /** - * @brief 64-bit integer - * - */ - using i64 = long long; - - /** - * @brief Unsigned 8-bit integer - * - */ - using u8 = unsigned char; - - /** - * @brief Unsigned 16-bit integer - * - */ - using u16 = unsigned short; - - /** - * @brief Unsigned 32-bit integer - * - */ - using u32 = unsigned int; - - /** - * @brief Unsigned 64-bit integer - * - */ - using u64 = unsigned long long; - - /** - * @brief 32-bit floating point number - * - */ - using f32 = float; - - /** - * @brief 64-bit double - * - */ - using f64 = double; - - /** - * @brief Asserts to guarantee that each type is of the correct size - * - */ - static_assert(sizeof(b8) == 1); - static_assert(sizeof(i8) == 1); - static_assert(sizeof(i16) == 2); - static_assert(sizeof(i32) == 4); - static_assert(sizeof(i64) == 8); - static_assert(sizeof(u8) == 1); - static_assert(sizeof(u16) == 2); - static_assert(sizeof(u32) == 4); - static_assert(sizeof(u64) == 8); - static_assert(sizeof(f32) == 4); - static_assert(sizeof(f64) == 8); -} // namespace Dynamo \ No newline at end of file diff --git a/src/Utils/Allocator.cpp b/src/Utils/Allocator.cpp index 40e2eb45..2be452c1 100644 --- a/src/Utils/Allocator.cpp +++ b/src/Utils/Allocator.cpp @@ -1,7 +1,8 @@ #include "./Allocator.hpp" +#include "./Log.hpp" namespace Dynamo { - Allocator::Allocator(u32 capacity) : _capacity(capacity) { + Allocator::Allocator(unsigned capacity) : _capacity(capacity) { // Create the initial free block that encompasses the heap Block heap_block; heap_block.offset = 0; @@ -17,8 +18,8 @@ namespace Dynamo { Log::info("Before defragmentation: {}", print()); #endif Block block = *it; - u32 new_offset = block.offset; - u32 new_size = block.size; + unsigned new_offset = block.offset; + unsigned new_size = block.size; // Join left node if (it != _free.begin()) { @@ -45,14 +46,14 @@ namespace Dynamo { #endif } - std::optional Allocator::reserve(u32 size, - u32 alignment) { + std::optional Allocator::reserve(unsigned size, + unsigned alignment) { for (auto it = _free.begin(); it != _free.end(); it++) { Block &block = *it; - u32 offset = align_size(block.offset, alignment); - u32 block_r = block.offset + block.size; - u32 alloc_r = offset + size; + unsigned offset = align_size(block.offset, alignment); + unsigned block_r = block.offset + block.size; + unsigned alloc_r = offset + size; if (block_r >= alloc_r) { // Handle allocation in the middle of the block due to alignment @@ -83,7 +84,7 @@ namespace Dynamo { return {}; } - void Allocator::free(u32 offset) { + void Allocator::free(unsigned offset) { if (_used.count(offset) == 0) { Log::error("Allocator::free() failed, invalid offset {}: {}", offset, @@ -103,7 +104,7 @@ namespace Dynamo { } // Start of the list - u32 alloc_r = freed.offset + freed.size; + unsigned alloc_r = freed.offset + freed.size; if (_free.begin()->offset >= alloc_r) { _free.push_front(freed); defragment(_free.begin()); @@ -111,7 +112,7 @@ namespace Dynamo { } for (auto it = _free.begin(); it != _free.end(); it++) { - u32 block_r = it->offset + it->size; + unsigned block_r = it->offset + it->size; // End of the list auto next = std::next(it); @@ -133,7 +134,7 @@ namespace Dynamo { DYN_ASSERT(false); } - void Allocator::grow(u32 capacity) { + void Allocator::grow(unsigned capacity) { #ifdef DYN_DEBUG Log::info("Before grow: {}", print()); #endif @@ -155,13 +156,13 @@ namespace Dynamo { #endif } - b8 Allocator::is_reserved(u32 offset) const { + bool Allocator::is_reserved(unsigned offset) const { return _used.count(offset) > 0; } - u32 Allocator::capacity() const { return _capacity; } + unsigned Allocator::capacity() const { return _capacity; } - u32 Allocator::size(u32 offset) const { return _used.at(offset); } + unsigned Allocator::size(unsigned offset) const { return _used.at(offset); } std::string Allocator::print() const { std::string str; @@ -176,7 +177,7 @@ namespace Dynamo { } while (it != _free.end()) { - u32 right = it->offset + it->size; + unsigned right = it->offset + it->size; str += " | " + std::to_string(it->offset) + ", " + std::to_string(right); diff --git a/src/Utils/Allocator.hpp b/src/Utils/Allocator.hpp index e88c1c4f..fdebe064 100644 --- a/src/Utils/Allocator.hpp +++ b/src/Utils/Allocator.hpp @@ -2,20 +2,18 @@ #include #include +#include #include -#include "../Log/Log.hpp" -#include "../Types.hpp" - namespace Dynamo { /** * @brief Round up a size to be a multiple of alignment. * * @param size Size in bytes. * @param alignment Alignment in bytes. - * @return u32 + * @return unsigned */ - inline u32 align_size(u32 size, u32 alignment) { + inline unsigned align_size(unsigned size, unsigned alignment) { return ((size + alignment - 1) / alignment) * alignment; } @@ -26,13 +24,13 @@ namespace Dynamo { */ class Allocator { struct Block { - u32 offset; - u32 size; + unsigned offset; + unsigned size; }; std::list _free; - std::unordered_map _used; + std::unordered_map _used; - u32 _capacity; + unsigned _capacity; /** * @brief Join adjacent blocks. @@ -47,7 +45,7 @@ namespace Dynamo { * * @param capacity Capacity of the heap. */ - Allocator(u32 capacity); + Allocator(unsigned capacity); /** * @brief Reserve a block of memory with specific alignment @@ -55,23 +53,23 @@ namespace Dynamo { * * @param size Desired size in bytes. * @param alignment Alignment requirement in bytes. - * @return std::optional + * @return std::optional */ - std::optional reserve(u32 size, u32 alignment); + std::optional reserve(unsigned size, unsigned alignment); /** * @brief Free the block of reserved memory at an offset. * * @param offset Offset within the pool in bytes returned by reserve(). */ - void free(u32 offset); + void free(unsigned offset); /** * @brief Grow the total capacity, expanding the free blocks. * * @param capacity New capacity in bytes >= current_capacity. */ - void grow(u32 capacity); + void grow(unsigned capacity); /** * @brief Check if an offset is mapped to a reserved block. @@ -80,22 +78,22 @@ namespace Dynamo { * @return true * @return false */ - b8 is_reserved(u32 offset) const; + bool is_reserved(unsigned offset) const; /** * @brief Get the capacity of the allocator. * - * @return u32 + * @return unsigned */ - u32 capacity() const; + unsigned capacity() const; /** * @brief Get the size of a reserved block. * * @param offset Offset within the pool in bytes returned by reserve(). - * @return u32 + * @return unsigned */ - u32 size(u32 offset) const; + unsigned size(unsigned offset) const; /** * @brief Generate the human-readable string to visualize the state diff --git a/src/Utils/Bits.hpp b/src/Utils/Bits.hpp index e3fbcc88..f9a18039 100644 --- a/src/Utils/Bits.hpp +++ b/src/Utils/Bits.hpp @@ -2,8 +2,6 @@ #include -#include "../Types.hpp" - namespace Dynamo { /** * @brief Table of constants for performing fast bit reversal. @@ -11,7 +9,7 @@ namespace Dynamo { * Taken from http://graphics.stanford.edu/~seander/bithacks.html * */ - constexpr std::array BIT_REVERSAL_TABLE = { + constexpr std::array BIT_REVERSAL_TABLE = { 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, @@ -41,7 +39,7 @@ namespace Dynamo { * position of the least significant bit. * */ - constexpr std::array DE_BRUJIN_TABLE = { + constexpr std::array DE_BRUJIN_TABLE = { 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9, }; @@ -51,10 +49,10 @@ namespace Dynamo { * 32-bit integer. * * @param x - * @return constexpr u32 + * @return constexpr unsigned */ - constexpr u32 find_lsb(u32 x) { - u32 i = ((x & -x) * 0x077CB531U); + constexpr unsigned find_lsb(unsigned x) { + unsigned i = ((x & -x) * 0x077CB531U); return DE_BRUJIN_TABLE[i >> 27]; } @@ -62,9 +60,9 @@ namespace Dynamo { * @brief Reverse the bits of an unsigned 32-bit integer. * * @param x - * @return constexpr u32 + * @return constexpr unsigned */ - constexpr u32 reverse_bits(u32 x) { + constexpr unsigned reverse_bits(unsigned x) { return (BIT_REVERSAL_TABLE[x & 0xFF] << 24) | (BIT_REVERSAL_TABLE[(x >> 8) & 0xFF] << 16) | (BIT_REVERSAL_TABLE[(x >> 16) & 0xFF] << 8) | @@ -75,9 +73,9 @@ namespace Dynamo { * @brief Round a number to the next power of 2. * * @param x - * @return constexpr u32 + * @return constexpr unsigned */ - constexpr u32 round_pow2(u32 x) { + constexpr unsigned round_pow2(unsigned x) { x--; x |= x >> 1; x |= x >> 2; diff --git a/src/Utils/ChannelData.hpp b/src/Utils/ChannelData.hpp index f610d880..a7ce19a4 100644 --- a/src/Utils/ChannelData.hpp +++ b/src/Utils/ChannelData.hpp @@ -3,8 +3,7 @@ #include #include -#include "../Log/Log.hpp" -#include "../Types.hpp" +#include "./Log.hpp" namespace Dynamo { /** @@ -19,8 +18,8 @@ namespace Dynamo { "ChannelData members must be trivially copyable"); std::vector _container; - u32 _channels; - u32 _frames; + unsigned _channels; + unsigned _frames; public: /** @@ -29,7 +28,7 @@ namespace Dynamo { * @param frames Number of frames. * @param channels Number of channels. */ - ChannelData(u32 frames = 0, u32 channels = 0) { + ChannelData(unsigned frames = 0, unsigned channels = 0) { resize(frames, channels); } @@ -39,7 +38,7 @@ namespace Dynamo { * @param data Data buffer. * @param channels Number of channels. */ - ChannelData(std::vector data, u32 channels) : + ChannelData(std::vector data, unsigned channels) : _container(data), _channels(channels), _frames(data.size() / channels) { DYN_ASSERT(data.size() % channels == 0); @@ -55,16 +54,16 @@ namespace Dynamo { /** * @brief Get the number of frames. * - * @return u32 + * @return unsigned */ - inline u32 frames() const { return _frames; } + inline unsigned frames() const { return _frames; } /** * @brief Get the number of channels. * - * @return u32 + * @return unsigned */ - inline u32 channels() const { return _channels; } + inline unsigned channels() const { return _channels; } /** * @brief Default-initialize all entries in the container. @@ -79,7 +78,7 @@ namespace Dynamo { * * @param frames Number of frames. */ - inline void set_frames(const u32 frames) { + inline void set_frames(const unsigned frames) { _container.resize(_channels * frames); _frames = frames; } @@ -89,7 +88,7 @@ namespace Dynamo { * * @param channels Number of channels. */ - inline void set_channels(const u32 channels) { + inline void set_channels(const unsigned channels) { _container.resize(channels * _frames); _channels = channels; } @@ -100,7 +99,7 @@ namespace Dynamo { * @param frames Number of frames. * @param channels Number of channels. */ - inline void resize(const u32 frames, const u32 channels) { + inline void resize(const unsigned frames, const unsigned channels) { _container.resize(channels * frames); _channels = channels; _frames = frames; @@ -112,9 +111,9 @@ namespace Dynamo { * @param dst Destination buffer. * @param frame Frame index. */ - inline void read_frame(T *dst, const u32 frame) const { + inline void read_frame(T *dst, const unsigned frame) const { DYN_ASSERT(frame < _frames); - for (u32 c = 0; c < _channels; c++) { + for (unsigned c = 0; c < _channels; c++) { dst[c] = _container[(c * _frames) + frame]; } } @@ -125,7 +124,7 @@ namespace Dynamo { * @param dst Destination buffer. * @param channel Channel index. */ - inline void read_channel(T *dst, const u32 channel) const { + inline void read_channel(T *dst, const unsigned channel) const { DYN_ASSERT(channel < _channels); const T *ptr = _container.data() + (channel * _frames); std::copy(ptr, ptr + _frames, dst); @@ -137,7 +136,7 @@ namespace Dynamo { * @param channel Channel index. * @return T* */ - inline T *operator[](const u32 channel) { + inline T *operator[](const unsigned channel) { DYN_ASSERT(channel < _channels); return _container.data() + (channel * _frames); } @@ -149,7 +148,7 @@ namespace Dynamo { * @param channel Channel index. * @return T */ - inline T at(const u32 frame, const u32 channel) const { + inline T at(const unsigned frame, const unsigned channel) const { DYN_ASSERT(frame < _frames); DYN_ASSERT(channel < _channels); return _container[(channel * _frames) + frame]; diff --git a/src/Utils/IdTracker.hpp b/src/Utils/IdTracker.hpp index 0a0e549e..091b384d 100644 --- a/src/Utils/IdTracker.hpp +++ b/src/Utils/IdTracker.hpp @@ -1,27 +1,24 @@ #pragma once -#include #include #include -#include "../Types.hpp" - namespace Dynamo { /** * @brief Unique identifier supports up to 2^32 - 1 entities simultaneously. * */ - using Id = u64; + using Id = unsigned long long; /** * @brief Generate and discard ids. * */ class IdTracker { - u32 _index_counter; + unsigned _index_counter; - std::vector _version_map; - std::queue _free_indices; + std::vector _version_map; + std::queue _free_indices; public: /** @@ -34,17 +31,17 @@ namespace Dynamo { * @brief Get the index of an id. * * @param id - * @return u32 + * @return unsigned */ - static inline u32 get_index(Id id) { return id >> 32; } + static inline unsigned get_index(Id id) { return id >> 32; } /** * @brief Get the version of an id. * * @param id - * @return u32 + * @return unsigned */ - static inline u32 get_version(Id id) { return id & 0xFFFFFFFF; } + static inline unsigned get_version(Id id) { return id & 0xFFFFFFFF; } /** * @brief Test if an id is active. @@ -53,9 +50,9 @@ namespace Dynamo { * @return true * @return false */ - inline b8 is_active(Id id) { - u32 index = IdTracker::get_index(id); - u32 version = IdTracker::get_version(id); + inline bool is_active(Id id) { + unsigned index = IdTracker::get_index(id); + unsigned version = IdTracker::get_version(id); return index < _index_counter && _version_map[index] == version; } @@ -68,7 +65,7 @@ namespace Dynamo { * @return Id */ inline Id generate() { - u32 index, version; + unsigned index, version; if (_free_indices.size() > 0) { index = _free_indices.front(); version = _version_map[index]; @@ -91,7 +88,7 @@ namespace Dynamo { */ inline void discard(Id id) { if (!is_active(id)) return; - u32 index = IdTracker::get_index(id); + unsigned index = IdTracker::get_index(id); _version_map[index]++; _free_indices.push(index); } diff --git a/src/Utils/Log.hpp b/src/Utils/Log.hpp new file mode 100644 index 00000000..910ff79e --- /dev/null +++ b/src/Utils/Log.hpp @@ -0,0 +1,82 @@ +#pragma once + +#ifndef NDEBUG +#define DYN_DEBUG +#endif + +#ifdef DYN_DEBUG +#define DYN_ASSERT(cond) \ + !(cond) ? Dynamo::Log::error("Assertion {} failed: {}, Line {}", \ + #cond, \ + __FILE__, \ + __LINE__) \ + : (void(0)) +#else +#define DYN_ASSERT(cond) (void(0)) +#endif + +#include +#include + +#include +#include + +#include "Clock.hpp" + +namespace Dynamo { + /** + * @brief Log helper. + * + */ + class Log { + public: + /** + * @brief Log an information string. + * + * @tparam Args + * @param fmt + * @param args + */ + template + static void info(std::string fmt = "", Args... args) { + std::string message = fmt::format(fmt, args...); + std::string line = fmt::format("[INFO {:%Y-%m-%d %H:%M:%S}] {}", + Clock::time(), + message); + std::cout << line << "\n"; + } + + /** + * @brief Log a warning. + * + * @tparam Args + * @param fmt + * @param args + */ + template + static void warn(std::string fmt, Args... args) { + std::string message = fmt::format(fmt, args...); + std::string line = fmt::format("[WARN {:%Y-%m-%d %H:%M:%S}] {}", + Clock::time(), + message); + std::cout << line << "\n"; + } + + /** + * @brief Log an error. This will throw an exception. + * + * @tparam Args + * @param fmt + * @param args + */ + template + static void error(std::string fmt, Args... args) { + std::string message = fmt::format(fmt, args...); + std::string line = fmt::format("[ERROR {:%Y-%m-%d %H:%M:%S}] {}", + Clock::time(), + message); + std::cout << line << "\n"; + throw std::runtime_error(message); + } + }; +} // namespace Dynamo \ No newline at end of file diff --git a/src/Utils/Random.hpp b/src/Utils/Random.hpp index 3d5438c9..f4cb9767 100644 --- a/src/Utils/Random.hpp +++ b/src/Utils/Random.hpp @@ -1,37 +1,33 @@ #pragma once -#include -#include #include -#include "../Types.hpp" - namespace Dynamo::Random { static std::default_random_engine rng; - static std::uniform_real_distribution uniform(0, 1); + static std::uniform_real_distribution uniform(0, 1); /** * @brief Seed the random number generator. * * @param s Seed value. */ - inline void seed(i32 s) { rng.seed(s); } + inline void seed(long long s) { rng.seed(s); } /** * @brief Get a random number in the range [0, 1). * - * @return f32 + * @return float */ - inline f32 random() { return uniform(rng); } + inline float random() { return uniform(rng); } /** * @brief Get a random number in the range [min, max). * * @param min Minimum value inclusive. * @param max Maximum value exclusive. - * @return f32 + * @return float */ - inline f32 range(f32 min, f32 max) { + inline float range(float min, float max) { return min + ((max - min) * random()); } } // namespace Dynamo::Random diff --git a/src/Utils/RingBuffer.hpp b/src/Utils/RingBuffer.hpp index 4bc5e94b..c70864ed 100644 --- a/src/Utils/RingBuffer.hpp +++ b/src/Utils/RingBuffer.hpp @@ -2,7 +2,7 @@ #include -#include "../Types.hpp" +#include "./Log.hpp" namespace Dynamo { /** @@ -16,17 +16,17 @@ namespace Dynamo { * @tparam T Type of element, must be trivially copyable. * @tparam N Maximum size of the container (power of 2). */ - template + template class RingBuffer { - static const u32 MASK = N - 1; + static const unsigned MASK = N - 1; static_assert(N > 0 && (N & MASK) == 0, "RingBuffer size (> 0) should be a power of 2"); static_assert(std::is_trivially_copyable::value, "RingBuffer element type must be trivially copyable"); std::array _buffer; - u32 _read; - u32 _write; + unsigned _read; + unsigned _write; public: /** @@ -41,7 +41,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 full() const { return size() == N; } + inline bool full() const { return size() == N; } /** * @brief Check if the buffer is empty @@ -49,21 +49,21 @@ namespace Dynamo { * @return true * @return false */ - inline b8 empty() const { return size() == 0; } + inline bool empty() const { return size() == 0; } /** * @brief Get the size of the buffer * - * @return u32 + * @return unsigned */ - inline u32 size() const { return (_write - _read); } + inline unsigned size() const { return (_write - _read); } /** * @brief Get the number of writes that can still be performed * - * @return u32 + * @return unsigned */ - inline u32 remaining() const { return N - size(); } + inline unsigned remaining() const { return N - size(); } /** * @brief Read a value from the buffer, advancing the read pointer @@ -93,14 +93,14 @@ namespace Dynamo { * * @param dst * @param n - * @return u32 + * @return unsigned */ - inline u32 read(T *dst, const u32 n) { + inline unsigned read(T *dst, const unsigned n) { // Compute copy partitions - u32 offset = _read & MASK; - u32 length = std::min(n, size()); - u32 l_length = std::min(length, N - offset); - u32 r_length = length - l_length; + unsigned offset = _read & MASK; + unsigned length = std::min(n, size()); + unsigned l_length = std::min(length, N - offset); + unsigned r_length = length - l_length; T *src = _buffer.data(); std::copy(src + offset, src + offset + l_length, dst); @@ -119,13 +119,13 @@ namespace Dynamo { * * @param src * @param n - * @return u32 + * @return unsigned */ - inline u32 write(const T *src, const u32 n) { + inline unsigned write(const T *src, const unsigned n) { // Compute copy partitions - u32 offset = _write & MASK; - u32 length = std::min(n, remaining()); - u32 l_length = std::min(length, N - offset); + unsigned offset = _write & MASK; + unsigned length = std::min(n, remaining()); + unsigned l_length = std::min(length, N - offset); T *dst = _buffer.data(); std::copy(src, src + l_length, dst + offset); diff --git a/src/Utils/SparseSet.hpp b/src/Utils/SparseSet.hpp index a27e3ee3..8056344c 100644 --- a/src/Utils/SparseSet.hpp +++ b/src/Utils/SparseSet.hpp @@ -3,9 +3,8 @@ #include #include -#include "../Log/Log.hpp" -#include "../Types.hpp" #include "./IdTracker.hpp" +#include "./Log.hpp" namespace Dynamo { /** @@ -50,15 +49,15 @@ namespace Dynamo { * @brief Contains indices to _dense and _pool * */ - std::vector _sparse; + std::vector _sparse; public: /** * @brief Get the number of items. * - * @return u32 + * @return unsigned */ - inline u32 size() const { return _pool.size(); } + inline unsigned size() const { return _pool.size(); } /** * @brief Check if the container is empty. @@ -66,23 +65,23 @@ namespace Dynamo { * @return true * @return false */ - inline b8 empty() const { return size() == 0; } + inline bool empty() const { return size() == 0; } /** * @brief Find the position of a value within the dense array. * * @param id Unique identifer. - * @return i32 Index position of the value (-1 on failure). + * @return int Index position of the value (-1 on failure). */ - inline i32 find(Id id) { - u32 key = IdTracker::get_index(id); + inline int find(Id id) { + unsigned key = IdTracker::get_index(id); if (key >= _sparse.size()) { return -1; } // Verify that the sparse and dense arrays are correlated - i32 index = _sparse[key]; - i32 dense_size = _dense.size(); + int index = _sparse[key]; + int dense_size = _dense.size(); if (index == -1 || index >= dense_size || _dense[index] != id) { return -1; } @@ -96,7 +95,7 @@ namespace Dynamo { * @return true * @return false */ - inline b8 exists(Id id) { return find(id) >= 0; } + inline bool exists(Id id) { return find(id) >= 0; } /** * @brief Create a new object in the pool and associate it with an id. @@ -110,7 +109,7 @@ namespace Dynamo { template inline void insert(Id id, Params... args) { // Resize the sparse array or remove the existing item - u32 key = IdTracker::get_index(id); + unsigned key = IdTracker::get_index(id); if (key >= _sparse.size()) { _sparse.resize((key + 1) * 2, -1); } else if (_sparse[key] != -1) { @@ -136,20 +135,20 @@ namespace Dynamo { * @param id Unique identifier of the object to be removed. */ inline void remove(Id id) { - u32 key = IdTracker::get_index(id); + unsigned key = IdTracker::get_index(id); if (key >= _sparse.size()) { return; } // Verify that the sparse and dense arrays are correlated - i32 index = _sparse[key]; - i32 dense_size = _dense.size(); + int index = _sparse[key]; + int dense_size = _dense.size(); if (index == -1 || index >= dense_size || _dense[index] != id) { return; } // Swap last element of dense and pool array to maintain contiguity - u32 new_key = IdTracker::get_index(_dense.back()); + unsigned new_key = IdTracker::get_index(_dense.back()); std::swap(_pool.back(), _pool[index]); _pool.pop_back(); @@ -177,9 +176,9 @@ namespace Dynamo { * @param index Index position of the object within the pool array. * @return T& */ - inline T &at(i32 index) { + inline T &at(int index) { DYN_ASSERT(index >= 0); - DYN_ASSERT(index < static_cast(_pool.size())); + DYN_ASSERT(index < static_cast(_pool.size())); return _pool[index]; } @@ -199,7 +198,7 @@ namespace Dynamo { */ template inline void forall(Functor &&function) { - for (i32 i = 0; i < size(); i++) { + for (unsigned i = 0; i < size(); i++) { function(_pool[i], _dense[i]); } } @@ -212,7 +211,7 @@ namespace Dynamo { */ template inline void forall_items(Functor &&function) { - for (i32 i = 0; i < size(); i++) { + for (int i = 0; i < size(); i++) { function(_pool[i]); } } @@ -225,7 +224,7 @@ namespace Dynamo { */ template inline void forall_ids(Functor &&function) { - for (i32 i = 0; i < size(); i++) { + for (int i = 0; i < size(); i++) { function(_dense[i]); } } diff --git a/src/Utils/ThreadPool.hpp b/src/Utils/ThreadPool.hpp index 52eb129e..5bf734b3 100644 --- a/src/Utils/ThreadPool.hpp +++ b/src/Utils/ThreadPool.hpp @@ -10,9 +10,6 @@ #include #include -#include "../Log/Log.hpp" -#include "../Types.hpp" - namespace Dynamo { /** * @brief A pool of threads to assign jobs that run concurrently. @@ -21,14 +18,14 @@ namespace Dynamo { class ThreadPool { std::vector _threads; std::queue> _jobs; - u32 _job_count = 0; + unsigned _job_count = 0; mutable std::mutex _mutex; std::condition_variable _conditional_start; std::condition_variable _conditional_finish; - b8 _terminate = false; - b8 _waiting = false; + bool _terminate = false; + bool _waiting = false; /** * @brief Main thread loop that waits for new jobs to execute. @@ -66,9 +63,9 @@ namespace Dynamo { * * @param pool_size Number of threads in the pool. */ - ThreadPool(u32 pool_size) { + ThreadPool(unsigned pool_size) { _threads.resize(pool_size); - for (u32 i = 0; i < pool_size; i++) { + for (unsigned i = 0; i < pool_size; i++) { _threads[i] = std::thread([this]() { thread_main(); }); } } diff --git a/src/Utils/TypeId.hpp b/src/Utils/TypeId.hpp index d661fd2b..2622fb8f 100644 --- a/src/Utils/TypeId.hpp +++ b/src/Utils/TypeId.hpp @@ -1,25 +1,23 @@ #pragma once -#include "../Types.hpp" - namespace Dynamo { /** * @brief Generate a unique identifier for a type at runtime. * */ class TypeId { - inline static u32 _id_counter = 0; + inline static unsigned _id_counter = 0; public: /** * @brief Get the unique identifier of a type. * * @tparam Type. - * @return u32 + * @return unsigned */ template - inline static u32 get() { - static const u32 id = _id_counter++; + inline static unsigned get() { + static const unsigned id = _id_counter++; return id; } }; diff --git a/submodules/fmt b/submodules/fmt index 51d3685e..891c9a73 160000 --- a/submodules/fmt +++ b/submodules/fmt @@ -1 +1 @@ -Subproject commit 51d3685efe0eb8a44656f9fd5dac6a04f4e58259 +Subproject commit 891c9a73ae9a23ed8bffffb8753504b1f6f399d0 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6ebb125d..8dde27ff 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,11 +4,9 @@ include(CTest) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED on) - -set(CMAKE_C_STANDARD 17) set(CMAKE_C_STANDARD_REQUIRED on) -add_compile_options(-Wall -g -O3) +add_compile_options(-Wall -g -O3 -fPIC) add_subdirectory("../" "./Dynamo") add_subdirectory("../submodules/Catch2" "./Catch2") diff --git a/tests/src/Box2-Test.cpp b/tests/src/Box2-Test.cpp index 4d255dc5..97aeaab0 100644 --- a/tests/src/Box2-Test.cpp +++ b/tests/src/Box2-Test.cpp @@ -1,5 +1,6 @@ #include #include +#include TEST_CASE("Box2 construct center and dimensions", "[Box2]") { Dynamo::Box2 a({0, 0}, 5, 5); diff --git a/tests/src/Circle-Test.cpp b/tests/src/Circle-Test.cpp index 22d61ca8..404b0c6f 100644 --- a/tests/src/Circle-Test.cpp +++ b/tests/src/Circle-Test.cpp @@ -1,5 +1,6 @@ #include #include +#include TEST_CASE("Circle circumference", "[Circle]") { Dynamo::Circle a({0, 0}, 5); diff --git a/tests/src/Complex-Test.cpp b/tests/src/Complex-Test.cpp index 313d5284..14dac7c5 100644 --- a/tests/src/Complex-Test.cpp +++ b/tests/src/Complex-Test.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include "Common.hpp" diff --git a/tests/src/Quaternion-Test.cpp b/tests/src/Quaternion-Test.cpp index c705a934..d1473aa8 100644 --- a/tests/src/Quaternion-Test.cpp +++ b/tests/src/Quaternion-Test.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "Common.hpp" diff --git a/tests/src/Segment-Test.cpp b/tests/src/Segment-Test.cpp index f3d7a64e..3c7fbf8b 100644 --- a/tests/src/Segment-Test.cpp +++ b/tests/src/Segment-Test.cpp @@ -1,5 +1,6 @@ #include #include +#include TEST_CASE("Segment2 length squared", "[Segment2]") { Dynamo::Segment2 a({0, 0}, {2, 0}); diff --git a/tests/src/Triangle2-Test.cpp b/tests/src/Triangle2-Test.cpp index bc6053f5..5279f4c0 100644 --- a/tests/src/Triangle2-Test.cpp +++ b/tests/src/Triangle2-Test.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "Common.hpp" diff --git a/tests/src/Vec2-Test.cpp b/tests/src/Vec2-Test.cpp index 45c851dd..8b8215be 100644 --- a/tests/src/Vec2-Test.cpp +++ b/tests/src/Vec2-Test.cpp @@ -1,5 +1,6 @@ #include #include +#include TEST_CASE("Vec2 length squared", "[Vec2]") { Dynamo::Vec2 a(3, 4); diff --git a/tests/src/Vec3-Test.cpp b/tests/src/Vec3-Test.cpp index 5310e781..b01a16b3 100644 --- a/tests/src/Vec3-Test.cpp +++ b/tests/src/Vec3-Test.cpp @@ -1,5 +1,6 @@ #include #include +#include TEST_CASE("Vec3 length squared", "[Vec3]") { Dynamo::Vec3 a(1, 2, 2);