diff --git a/CMakeLists.txt b/CMakeLists.txt index 9bf010c..6d6e0a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,5 @@ add_subdirectory(FastRTTI) add_subdirectory(glfw) add_subdirectory(Core) add_subdirectory(ModuleLib) -add_subdirectory(RenderModule) add_subdirectory(TestGame) add_subdirectory(ProjectGenerator) diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index 83fcbdd..7b97125 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -2,8 +2,6 @@ set(CORE_NAME Core) find_package(Vulkan REQUIRED) -set(CORE_NAME Core) - file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp") add_library(${CORE_NAME} STATIC ${SRC}) diff --git a/Core/Core/CoreInstance.cpp b/Core/Core/CoreInstance.cpp index 30e719b..e6fb345 100644 --- a/Core/Core/CoreInstance.cpp +++ b/Core/Core/CoreInstance.cpp @@ -1,17 +1,22 @@ #include "CoreInstance.h" #include "SystemCalls.h" -#include "GLFW/glfw3.h" #include #include #include #include +#include +#include "RenderEngine.h" +#include "Game/GameInstance.h" #include "Log/Log.h" +#include "Game/SaveMap/SaveMap.h" CoreInstance* CoreInstance::self = nullptr; +extern GameInstance* GameFactory(CoreInstance&); + std::shared_ptr CoreInstance::MainConfig::save() { return std::make_shared("MainConfig"); @@ -28,7 +33,7 @@ void CoreInstance::MainConfig::load(std::shared_ptr save) void CoreInstance::Quit_callback() { - self->game->quit(); + self->game_->quit(); } CoreInstance::CoreInstance() @@ -37,16 +42,8 @@ CoreInstance::CoreInstance() callbacks_.Quit = &Quit_callback; - countCPU = System::getCountCPU(); - memorySize = System::getMemorySize(); - - if (!glfwInit()) - { - std::string msg; - const char* error; - glfwGetError(&error); - throw std::runtime_error("Fail initialize GLFW"); - } + countCPU_ = System::getCountCPU(); + memorySize_ = System::getMemorySize(); std::ifstream main_config_file(main_config_name); if (main_config_file.fail()) @@ -56,35 +53,51 @@ CoreInstance::CoreInstance() std::getline(main_config_file, payload); SaveMap load_main_config(payload); - main_config.load(std::make_shared(load_main_config)); + main_config_.load(std::make_shared(load_main_config)); + + if (glfwInit() == GLFW_FALSE) + throw std::runtime_error("Fail init glfw"); + + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + window_ = glfwCreateWindow(800, 600, main_config_.game_name.c_str(), nullptr, nullptr); + if (window_ == nullptr) + { + glfwTerminate(); + throw std::runtime_error("Fail create window"); + } + render_engine_ = new RenderEngine(*this, window_); + + game_ = GameFactory(*this); + if (game_ == nullptr) + throw std::runtime_error("Fail create game instance!"); } CoreInstance::~CoreInstance() { - delete game; - - for (auto& module : modules) + for (auto& module : modules_) System::QuitModule(module.handler); - modules.clear(); -} + modules_.clear(); -extern GameInstance* GameFactory(CoreInstance&); + delete render_engine_; + delete game_; +} void CoreInstance::start() { - for (auto& name : main_config.modules_names) + for (auto& name : main_config_.modules_names) { try { void* handler = System::InitModule(name.c_str(), &callbacks_); - modules.push_back(Module {name.c_str(), handler}); + modules_.push_back(Module {name.c_str(), handler}); } catch (const std::exception& e) { std::cout << e.what() << '\n'; } } - for (auto& module : modules) + for (auto& module : modules_) { try { @@ -95,15 +108,21 @@ void CoreInstance::start() } } - game = GameFactory(*this); - if (game == nullptr) - throw std::runtime_error("Fail create game instance!"); - game->start(); + std::thread game_thread(&GameInstance::start, game_); + render_engine_->start(); + game_->stop(); + game_thread.join(); +} + +void CoreInstance::quit() +{ + // Stop the main loop + render_engine_->stop_render(); } void* CoreInstance::getHandlerModule(const char* name) const { - for (const auto& module : modules) + for (const auto& module : modules_) { if (std::strcmp(module.name, name) == 0) return module.handler; @@ -113,25 +132,25 @@ void* CoreInstance::getHandlerModule(const char* name) const void* CoreInstance::enableModule(const char* name) { - for (const auto& module : modules) + for (const auto& module : modules_) { if (std::strcmp(module.name, name) == 0) throw std::runtime_error("Module already enabled"); } void* module = System::InitModule(name, &callbacks_); - modules.push_back({ name, module }); + modules_.push_back({ name, module }); return module; } void CoreInstance::disableModule(const char* name) { - for (auto i = modules.cbegin(); i != modules.cend(); ++i) + for (auto i = modules_.cbegin(); i != modules_.cend(); ++i) { if (std::strcmp(i->name, name) == 0) { System::QuitModule(i->handler); - modules.erase(i); + modules_.erase(i); break; } } diff --git a/Core/Core/CoreInstance.h b/Core/Core/CoreInstance.h index 9668f1c..43ee59f 100644 --- a/Core/Core/CoreInstance.h +++ b/Core/Core/CoreInstance.h @@ -2,13 +2,18 @@ #include #include +#include +#include -#include "Game/GameInstance.h" -#include "Game/SaveMap/SaveMap.h" +#include "Game/SaveMap/ISave.h" #include "Core/CoreCallBacks.h" +class SaveMap; +class RenderEngine; +class GameInstance; +struct GLFWwindow; + class CoreInstance { - static CoreInstance* self; struct Module { const char* name; void* handler; @@ -21,21 +26,25 @@ class CoreInstance { std::vector modules_names; double min_memory_size = -1; - int min_CPU_count = -1; + long long min_CPU_count = -1; std::shared_ptr save() override; void load(std::shared_ptr save) override; }; const char* main_config_name = "main_config.conf"; - MainConfig main_config; + MainConfig main_config_; - int countCPU; + int countCPU_; // Memory in MB - double memorySize; - std::list modules; + double memorySize_; + std::list modules_; - GameInstance* game = nullptr; + GLFWwindow* window_ = nullptr; + RenderEngine* render_engine_; + GameInstance* game_; + + static CoreInstance* self; CoreCallBacks callbacks_; #pragma region Callbacks @@ -46,15 +55,13 @@ public: ~CoreInstance(); void start(); - - /** - * This method quit game - * Async - */ + void quit(); + + int getCountCPU() const { return countCPU_; } + double getMemorySize() const { return memorySize_; } + const std::string& getBaseWorldName() const { return main_config_.base_world; } + const std::string& getGameName() const { return main_config_.game_name; } - int getCountCPU() const { return countCPU; } - double getMemorySize() const { return memorySize; } - /** * @throws std::runtime_error if module isn't enabled * @throws std::runtime_error if module not found @@ -73,7 +80,4 @@ public: * @throws std::runtime_error module isn't contain QuitModule function */ void disableModule(const char* name) noexcept(false); - - const std::string& getBaseWorldName() const { return main_config.base_world; } - const std::string& getGameName() const { return main_config.game_name; } }; diff --git a/Core/Core/Linux.cpp b/Core/Core/Linux.cpp deleted file mode 100644 index 4e93d75..0000000 --- a/Core/Core/Linux.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifdef __linux__ - -#include "SystemCalls.h" - -#include -#include -#include - -#include -#include - -int System::getCountCPU() -{ - int num_cores = sysconf(_SC_NPROCESSORS_ONLN); - if(num_cores <= 0) - throw std::runtime_error("Fail get number of cores"); - - return num_cores; -} - -double System::getMemorySize() -{ - struct sysinfo info{}; - if(sysinfo(&info) == -1) - std::runtime_error("Fail get system info"); - return info.totalram / 1024 / 1024; -} - -void* System::InitModule(const char* ModuleName, CoreInstance& core) -{ - std::string fileName = "./lib"; - fileName += ModuleName; - fileName += ".so"; - - void* handler = dlopen(fileName.c_str(), RTLD_NOW); - if(handler == nullptr) - throw std::runtime_error("Module not found"); - - void(*init)(CoreInstance&) = reinterpret_cast(dlsym(handler, "InitModule")); - if(init == nullptr) - throw std::runtime_error("Module not contains InitModule"); - init(core); - - return handler; -} - -void System::StartModule(void* handler) -{ - void(*start)() = reinterpret_cast(dlsym(handler, "StartModule")); - if(start == nullptr) - throw std::runtime_error("Module not contins StartModule"); - start(); -} - -void System::QuitModule(void* handler) -{ - void(*quit)() = reinterpret_cast(dlsym(handler, "QuitModule")); - if(quit == nullptr) - throw std::runtime_error("Module not contains QuitModule"); - quit(); - dlclose(handler); -} - -#endif diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine.cpp new file mode 100644 index 0000000..d4c4d5c --- /dev/null +++ b/Core/Core/RenderEngine.cpp @@ -0,0 +1,994 @@ +#include "RenderEngine.h" + +#include +#include +#include +#include + +#include "CoreInstance.h" +#include "Log/Log.h" + +#include "GLFW/glfw3.h" + +const std::vector RenderEngine::deviceExtensions = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME +}; + +#ifdef _DEBUG +static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData) { + + std::string msg = "validation layer: "; + msg += pCallbackData->pMessage; + Log(msg); + + return VK_FALSE; +} + +VkResult RenderEngine::enable_layer_validation(const VkDebugUtilsMessengerCreateInfoEXT* create_info) +{ + PFN_vkCreateDebugUtilsMessengerEXT debug_creator = reinterpret_cast(vkGetInstanceProcAddr(instance_, "vkCreateDebugUtilsMessengerEXT")); + return debug_creator(instance_, create_info, nullptr, &debug_messenger_); +} +#endif + +RenderEngine::SwapchainSupportDetails RenderEngine::query_swapchain_details() const +{ + SwapchainSupportDetails details; + + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device_, surface_, &details.capabilities); + + uint32_t surface_format_cnt = 0; + VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device_, surface_, &surface_format_cnt, nullptr)); + details.formats.resize(surface_format_cnt); + VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device_, surface_, &surface_format_cnt, details.formats.data())); + + uint32_t present_modes_cnt = 0; + VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device_, surface_, &present_modes_cnt, nullptr)); + details.present_modes.resize(surface_format_cnt); + VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device_, surface_, &present_modes_cnt, details.present_modes.data())); + + return details; +} + +std::vector RenderEngine::get_required_extensions() +{ + uint32_t extensions_count = 0; + const char** glfw_extension = glfwGetRequiredInstanceExtensions(&extensions_count); + std::vector extensions(glfw_extension, glfw_extension + extensions_count); + +#ifdef _DEBUG + extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); +#endif + return extensions; +} + +VkVertexInputBindingDescription RenderEngine::Vertex::get_binding_description() +{ + VkVertexInputBindingDescription description; + description.binding = 0; + description.stride = sizeof(Vertex); + description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + return description; +} + +std::array RenderEngine::Vertex::get_vertex_attribute_descriptions() +{ + std::array descriptions; + descriptions[0].binding = 0; + descriptions[0].location = 0; + descriptions[0].format = VK_FORMAT_R32G32_SFLOAT; + descriptions[0].offset = offsetof(Vertex, pos); + descriptions[1].binding = 0; + descriptions[1].location = 1; + descriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT; + descriptions[1].offset = offsetof(Vertex, color); + + return descriptions; +} + +bool RenderEngine::is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface) +{ + VkPhysicalDeviceProperties device_properties; + VkPhysicalDeviceFeatures device_features; + vkGetPhysicalDeviceProperties(device, &device_properties); + vkGetPhysicalDeviceFeatures(device, &device_features); + + try { + QueueFamilyIndices indices = find_queue_family_indices(device, surface); + } catch (...) { + return false; + } + + return check_device_extensions_support(device); +} + +bool RenderEngine::check_device_extensions_support(VkPhysicalDevice device) +{ + uint32_t extension_count; + VK_CHECK(vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, nullptr)); + std::vector available_extensions(extension_count); + VK_CHECK(vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, available_extensions.data())); + + for (const auto& extension : deviceExtensions) + { + bool isFind = false; + for (const auto& i : available_extensions) + { + if (std::strcmp(i.extensionName, extension) == 0) + { + isFind = true; + break; + } + } + if (!isFind) + return false; + } + return true; +} + +RenderEngine::QueueFamilyIndices RenderEngine::find_queue_family_indices(VkPhysicalDevice physical_device, VkSurfaceKHR surface) +{ + QueueFamilyIndices queue_family_indices; + + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, nullptr); + std::vector family_properties(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, family_properties.data()); + + // Find graphics + for(uint32_t i = 0; i < family_properties.size(); ++i) + { + if (family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) + { + queue_family_indices.graphics_family = i; + break; + } + } + + if (queue_family_indices.graphics_family.has_value() == false) + throw std::runtime_error("Failed to find a graphics queue family"); + + // Find present + VkBool32 present_support = false; + VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue_family_indices.graphics_family.value(), surface, &present_support)); + if (present_support == VK_TRUE) + queue_family_indices.present_family = queue_family_indices.graphics_family; + else + { + for(uint32_t i = 0; i < family_properties.size(); ++i) + { + present_support = false; + VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, surface, &present_support)); + if (present_support == VK_TRUE) + { + queue_family_indices.present_family = i; + break; + } + } + } + + if (queue_family_indices.present_family.has_value() == false) + throw std::runtime_error("Failed to find a present queue family"); + + for(uint32_t i = 0; i < family_properties.size(); ++i) + { + if (i == queue_family_indices.graphics_family.value()) + continue; + if (family_properties[i].queueFlags & VK_QUEUE_TRANSFER_BIT) + queue_family_indices.transfer_family = i; + } + if (queue_family_indices.transfer_family.has_value() == false) + queue_family_indices.transfer_family = queue_family_indices.graphics_family; + return queue_family_indices; +} + +VkSurfaceFormatKHR RenderEngine::choose_surface_format(const std::vector& surface_formats) +{ + for (const auto& i : surface_formats) + { + if (i.format == VK_FORMAT_B8G8R8A8_SRGB && i.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + return i; + } + return surface_formats[0]; +} + +VkPresentModeKHR RenderEngine::choose_present_mode(const std::vector& present_modes, VkPresentModeKHR desired_present_mode) +{ + for (const auto& i : present_modes) + { + if (i == desired_present_mode) + return i; + } + return VK_PRESENT_MODE_FIFO_KHR; +} + +VkExtent2D RenderEngine::choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window) +{ + if (capabilities.currentExtent.width != std::numeric_limits::max()) + return capabilities.currentExtent; + else + { + int width, height; + glfwGetFramebufferSize(window, &width, &height); + VkExtent2D actualExtent = { + static_cast(width), + static_cast(height) + }; + actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); + return actualExtent; + } +} + +VkShaderModule RenderEngine::create_shader_module(const std::string& code) const +{ + VkShaderModuleCreateInfo shader_module_info{}; + shader_module_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + shader_module_info.codeSize = code.size(); + shader_module_info.pCode = reinterpret_cast(code.c_str()); + + VkShaderModule shader_module; + VK_CHECK(vkCreateShaderModule(device_, &shader_module_info, nullptr, &shader_module)); + return shader_module; +} + +void RenderEngine::create_buffer(VkDeviceSize size, VkBufferUsageFlags usage, + VkBuffer* buffer, const std::vector& queue_families) +{ + VkBufferCreateInfo buffer_info{}; + buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_info.size = size; + buffer_info.usage = usage; + + if (queue_families.size() > 1) + { + buffer_info.sharingMode = VK_SHARING_MODE_CONCURRENT; + buffer_info.queueFamilyIndexCount = static_cast(queue_families.size()); + buffer_info.pQueueFamilyIndices = queue_families.data(); + } + else + { + buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + buffer_info.queueFamilyIndexCount = 0; + buffer_info.pQueueFamilyIndices = nullptr; + } + + VK_CHECK(vkCreateBuffer(device_, &buffer_info, nullptr, buffer)); +} + +void RenderEngine::allocate_memory(VkBuffer buffer, VkMemoryPropertyFlags property, VkDeviceMemory* device_memory) +{ + VkMemoryRequirements requirements{}; + vkGetBufferMemoryRequirements(device_, buffer, &requirements); + + VkMemoryAllocateInfo allocate_info{}; + allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocate_info.allocationSize = requirements.size; + allocate_info.memoryTypeIndex = find_memory_type(requirements.memoryTypeBits, property); + + VK_CHECK(vkAllocateMemory(device_, &allocate_info, nullptr, device_memory)); +} + +void RenderEngine::create_instance() +{ + std::vector extensions = get_required_extensions(); + + VkApplicationInfo app_info{}; + app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + app_info.apiVersion = VK_API_VERSION_1_0; + app_info.applicationVersion = VK_MAKE_VERSION(0, 0, 0); + app_info.pApplicationName = core_.getGameName().c_str(); + app_info.pEngineName = "UwU Engine"; + app_info.engineVersion = VK_MAKE_VERSION(0, 0, 0); + + + VkInstanceCreateInfo instance_create_info{}; + instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + instance_create_info.pApplicationInfo = &app_info; + instance_create_info.enabledExtensionCount = static_cast(extensions.size()); + instance_create_info.ppEnabledExtensionNames = extensions.data(); +#ifdef _DEBUG + const std::vector layers_validation = { + "VK_LAYER_KHRONOS_validation" + }; + instance_create_info.enabledLayerCount = static_cast(layers_validation.size()); + instance_create_info.ppEnabledLayerNames = layers_validation.data(); + VkDebugUtilsMessengerCreateInfoEXT debug_messenger_create_info{}; + debug_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + debug_messenger_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + debug_messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + debug_messenger_create_info.pfnUserCallback = &debugCallback; + instance_create_info.pNext = &debug_messenger_create_info; +#endif + VK_CHECK(vkCreateInstance(&instance_create_info, nullptr, &instance_)); +#ifdef _DEBUG + VK_CHECK(enable_layer_validation(&debug_messenger_create_info)); +#endif +} + +void RenderEngine::pick_physical_device() +{ + uint32_t device_count = 0; + std::vector devices; + VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, nullptr)); + devices.resize(device_count); + VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, devices.data())); + + for (const auto& device : devices) + { + if (is_device_suitable(device, surface_)) + { + physical_device_ = device; + VkPhysicalDeviceProperties device_properties; + vkGetPhysicalDeviceProperties(physical_device_, &device_properties); + Log("Using device: " + std::string(device_properties.deviceName)); + break; + } + } + + if (VK_NULL_HANDLE == physical_device_) + throw std::runtime_error("No suitable device found"); + } + +void RenderEngine::create_logical_device() +{ + QueueFamilyIndices indices = find_queue_family_indices(physical_device_, surface_); + + VkPhysicalDeviceFeatures device_features{}; + + std::vector queue_create_infos; + std::set unique_queue_families = {indices.graphics_family.value(), + indices.present_family.value(), + indices.transfer_family.value()}; + + float queue_priority = 1.0f; + VkDeviceQueueCreateInfo device_queue_create_info{}; + device_queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + device_queue_create_info.pQueuePriorities = &queue_priority; + for (auto queue_family : unique_queue_families) + { + device_queue_create_info.queueFamilyIndex = queue_family; + device_queue_create_info.queueCount = 1; + queue_create_infos.push_back(device_queue_create_info); + } + + VkDeviceCreateInfo device_create_info{}; + device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + device_create_info.queueCreateInfoCount = static_cast(unique_queue_families.size()); + device_create_info.pQueueCreateInfos = queue_create_infos.data(); + device_create_info.pEnabledFeatures = &device_features; + device_create_info.enabledExtensionCount = static_cast(deviceExtensions.size()); + device_create_info.ppEnabledExtensionNames = deviceExtensions.data(); + +#ifdef _DEBUG + const std::vector layers_validation = { + "VK_LAYER_KHRONOS_validation" + }; + device_create_info.enabledLayerCount = static_cast(layers_validation.size()); + device_create_info.ppEnabledLayerNames = layers_validation.data(); +#else + device_create_info.enabledLayerCount = 0; + device_create_info.ppEnabledLayerNames = nullptr; + +#endif + VK_CHECK(vkCreateDevice(physical_device_, &device_create_info, nullptr, &device_)); + vkGetDeviceQueue(device_, indices.graphics_family.value(), 0, &graphics_queue_); + vkGetDeviceQueue(device_, indices.present_family.value(), 0, &present_queue_); + vkGetDeviceQueue(device_, indices.transfer_family.value(), 0, &transfer_queue_); +} + +void RenderEngine::create_swapchain(VkPresentModeKHR desired_present_mode) +{ + SwapchainSupportDetails swapchain_support = query_swapchain_details(); + VkSurfaceFormatKHR surface_format = choose_surface_format(swapchain_support.formats); + VkPresentModeKHR present_mode = choose_present_mode(swapchain_support.present_modes, desired_present_mode); + VkExtent2D extent = choose_extent(swapchain_support.capabilities, window_); + + uint32_t image_count = swapchain_support.capabilities.minImageCount + 1; + if (swapchain_support.capabilities.maxImageCount > 0 && image_count > swapchain_support.capabilities.maxImageCount) + image_count = swapchain_support.capabilities.maxImageCount; + + VkSwapchainCreateInfoKHR swapchain_create_info{}; + swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + swapchain_create_info.surface = surface_; + swapchain_create_info.minImageCount = image_count; + swapchain_create_info.imageFormat = surface_format.format; + swapchain_create_info.imageColorSpace = surface_format.colorSpace; + swapchain_create_info.imageExtent = extent; + swapchain_create_info.imageArrayLayers = 1; + swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapchain_create_info.preTransform = swapchain_support.capabilities.currentTransform; + swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + swapchain_create_info.presentMode = present_mode; + swapchain_create_info.clipped = VK_TRUE; + swapchain_create_info.oldSwapchain = VK_NULL_HANDLE; + + QueueFamilyIndices family_indices = find_queue_family_indices(physical_device_, surface_); + const std::set queue_family_indices = { family_indices.graphics_family.value(), + family_indices.present_family.value(), + family_indices.transfer_family.value() }; + std::vector arr_families; + if (queue_family_indices.size() > 1) + { + arr_families.reserve(queue_family_indices.size()); + for(auto& i : queue_family_indices) + arr_families.push_back(i); + + + swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + swapchain_create_info.queueFamilyIndexCount = static_cast(arr_families.size()); + swapchain_create_info.pQueueFamilyIndices = arr_families.data(); + } + else + { + swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapchain_create_info.queueFamilyIndexCount = 0; + swapchain_create_info.pQueueFamilyIndices = nullptr; + } + + VK_CHECK(vkCreateSwapchainKHR(device_, &swapchain_create_info, nullptr, &swapchain_)); + + vkGetSwapchainImagesKHR(device_, swapchain_, &image_count, nullptr); + swapchain_images_.resize(image_count); + vkGetSwapchainImagesKHR(device_, swapchain_, &image_count, swapchain_images_.data()); + + swapchain_image_format_ = surface_format.format; + swapchain_extent_ = extent; +} + +void RenderEngine::create_image_views() +{ + VkImageViewCreateInfo image_view_info{}; + image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + image_view_info.format = swapchain_image_format_; + image_view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + image_view_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + image_view_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + image_view_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_view_info.subresourceRange.baseMipLevel = 0; + image_view_info.subresourceRange.levelCount = 1; + image_view_info.subresourceRange.baseArrayLayer = 0; + image_view_info.subresourceRange.layerCount = 1; + + swapchain_image_views_.resize(swapchain_images_.size()); + for (uint32_t i = 0; i < swapchain_images_.size(); ++i) + { + image_view_info.image = swapchain_images_[i]; + VK_CHECK(vkCreateImageView(device_, &image_view_info, nullptr, &swapchain_image_views_[i])); + } +} + +void RenderEngine::create_render_pass() +{ + VkAttachmentDescription attachment_description{}; + attachment_description.format = swapchain_image_format_; + attachment_description.samples = VK_SAMPLE_COUNT_1_BIT; + attachment_description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachment_description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment_description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment_description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachment_description.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + VkAttachmentReference attachment_reference; + attachment_reference.attachment = 0; + attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass_description{}; + subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass_description.colorAttachmentCount = 1; + subpass_description.pColorAttachments = &attachment_reference; + + VkSubpassDependency dependency{}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.srcAccessMask = 0; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + + VkRenderPassCreateInfo render_pass_info{}; + render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + render_pass_info.attachmentCount = 1; + render_pass_info.pAttachments = &attachment_description; + render_pass_info.subpassCount = 1; + render_pass_info.pSubpasses = &subpass_description; + render_pass_info.dependencyCount = 1; + render_pass_info.pDependencies = &dependency; + + VK_CHECK(vkCreateRenderPass(device_, &render_pass_info, nullptr, &render_pass_)); +} + +void RenderEngine::create_graphics_pipeline() +{ + std::ifstream vertex_shader_file("Shaders/vertex.spv", std::ios::binary); + if (!vertex_shader_file.is_open()) + throw std::runtime_error("Vertex shader not found"); + std::ifstream fragment_shader_file("Shaders/fragment.spv", std::ios::binary); + if (!fragment_shader_file.is_open()) { + vertex_shader_file.close(); + throw std::runtime_error("Fragment shader not found"); + } + + std::string vertex_shader_code((std::istreambuf_iterator(vertex_shader_file)), std::istreambuf_iterator()); + std::string fragment_shader_code((std::istreambuf_iterator(fragment_shader_file)), std::istreambuf_iterator()); + vertex_shader_file.close(); + fragment_shader_file.close(); + + VkShaderModule vertex_shader = create_shader_module(vertex_shader_code); + VkShaderModule fragment_shader = create_shader_module(fragment_shader_code); + + VkPipelineShaderStageCreateInfo vertex_shader_stage_info{}; + vertex_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vertex_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; + vertex_shader_stage_info.module = vertex_shader; + vertex_shader_stage_info.pName = "main"; + + VkPipelineShaderStageCreateInfo fragment_shader_stage_info{}; + fragment_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + fragment_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + fragment_shader_stage_info.module = fragment_shader; + fragment_shader_stage_info.pName = "main"; + + VkPipelineShaderStageCreateInfo shader_stages[] = {vertex_shader_stage_info, fragment_shader_stage_info}; + const std::vector dynamic_states = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR + }; + + VkPipelineDynamicStateCreateInfo dynamic_state_info{}; + dynamic_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_state_info.dynamicStateCount = static_cast(dynamic_states.size()); + dynamic_state_info.pDynamicStates = dynamic_states.data(); + + VkVertexInputBindingDescription binding_description = Vertex::get_binding_description(); + std::array attribute_descriptions = Vertex::get_vertex_attribute_descriptions(); + + VkPipelineVertexInputStateCreateInfo vertex_input_info{}; + vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertex_input_info.vertexBindingDescriptionCount = 1; + vertex_input_info.pVertexBindingDescriptions = &binding_description; + vertex_input_info.vertexAttributeDescriptionCount = static_cast(attribute_descriptions.size()); + vertex_input_info.pVertexAttributeDescriptions = attribute_descriptions.data(); + + VkPipelineInputAssemblyStateCreateInfo input_assembly_info{}; + input_assembly_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + input_assembly_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + input_assembly_info.primitiveRestartEnable = VK_FALSE; + + VkViewport viewport{}; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = static_cast(swapchain_extent_.width); + viewport.height = static_cast(swapchain_extent_.height); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor{}; + scissor.offset = {0, 0}; + scissor.extent = swapchain_extent_; + + VkPipelineViewportStateCreateInfo viewport_info{}; + viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport_info.viewportCount = 1; + viewport_info.pViewports = &viewport; + viewport_info.scissorCount = 1; + viewport_info.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterization_info{}; + rasterization_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterization_info.depthClampEnable = VK_FALSE; + rasterization_info.rasterizerDiscardEnable = VK_FALSE; + rasterization_info.polygonMode = VK_POLYGON_MODE_FILL; + rasterization_info.lineWidth = 1.0f; + rasterization_info.cullMode = VK_CULL_MODE_BACK_BIT; + rasterization_info.frontFace = VK_FRONT_FACE_CLOCKWISE; + rasterization_info.depthBiasEnable = VK_FALSE; + + VkPipelineMultisampleStateCreateInfo multisample_info{}; + multisample_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisample_info.sampleShadingEnable = VK_FALSE; + multisample_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + VkPipelineColorBlendAttachmentState color_blend_attachment_state{}; + color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + color_blend_attachment_state.blendEnable = VK_TRUE; + color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD; + + VkPipelineColorBlendStateCreateInfo color_blend_info{}; + color_blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + color_blend_info.logicOpEnable = VK_FALSE; + color_blend_info.attachmentCount = 1; + color_blend_info.pAttachments = &color_blend_attachment_state; + color_blend_info.blendConstants[0] = 0.0f; + color_blend_info.blendConstants[1] = 0.0f; + color_blend_info.blendConstants[2] = 0.0f; + color_blend_info.blendConstants[3] = 0.0f; + + VkPipelineLayoutCreateInfo pipeline_layout_info{}; + pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + + VK_CHECK(vkCreatePipelineLayout(device_, &pipeline_layout_info, nullptr, &pipeline_layout_)); + + VkGraphicsPipelineCreateInfo graphics_pipeline_info{}; + graphics_pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + graphics_pipeline_info.stageCount = 2; + graphics_pipeline_info.pStages = shader_stages; + graphics_pipeline_info.layout = pipeline_layout_; + graphics_pipeline_info.pColorBlendState = &color_blend_info; + graphics_pipeline_info.pDynamicState = &dynamic_state_info; + graphics_pipeline_info.pInputAssemblyState = &input_assembly_info; + graphics_pipeline_info.pMultisampleState = &multisample_info; + graphics_pipeline_info.pRasterizationState = &rasterization_info; + graphics_pipeline_info.pViewportState = &viewport_info; + graphics_pipeline_info.pVertexInputState = &vertex_input_info; + graphics_pipeline_info.pDepthStencilState = nullptr; + graphics_pipeline_info.renderPass = render_pass_; + graphics_pipeline_info.subpass = 0; + graphics_pipeline_info.basePipelineHandle = nullptr; + graphics_pipeline_info.basePipelineIndex = -1; + + VK_CHECK(vkCreateGraphicsPipelines(device_, nullptr, 1, &graphics_pipeline_info, nullptr, &graphics_pipeline_)); + + vkDestroyShaderModule(device_, vertex_shader, nullptr); + vkDestroyShaderModule(device_, fragment_shader, nullptr); +} + +void RenderEngine::create_framebuffers() +{ + framebuffers_.resize(swapchain_images_.size()); + + VkFramebufferCreateInfo framebuffer_info{}; + framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebuffer_info.renderPass = render_pass_; + framebuffer_info.attachmentCount = 1; + framebuffer_info.width = swapchain_extent_.width; + framebuffer_info.height = swapchain_extent_.height; + framebuffer_info.layers = 1; + + for (size_t i = 0; i < framebuffers_.size(); ++i) + { + framebuffer_info.pAttachments = &swapchain_image_views_[i]; + VK_CHECK(vkCreateFramebuffer(device_, &framebuffer_info, nullptr, &framebuffers_[i])); + } +} + +void RenderEngine::create_command_pool() +{ + QueueFamilyIndices queue_family_indices = find_queue_family_indices(physical_device_, surface_); + + VkCommandPoolCreateInfo command_pool_info{}; + command_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + command_pool_info.queueFamilyIndex = queue_family_indices.graphics_family.value(); + command_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + + VK_CHECK(vkCreateCommandPool(device_, &command_pool_info, nullptr, &command_pool_)); +} + +uint32_t RenderEngine::find_memory_type(uint32_t typeFilter, VkMemoryPropertyFlags properties) const +{ + VkPhysicalDeviceMemoryProperties memory_properties{}; + vkGetPhysicalDeviceMemoryProperties(physical_device_, &memory_properties); + + for (uint32_t i = 0; i < memory_properties.memoryTypeCount; ++i) + { + if (typeFilter & (1 << i) && (memory_properties.memoryTypes[i].propertyFlags & properties) == properties) + return i; + } + + throw std::runtime_error("failed to find suitable memory type!"); +} + +void RenderEngine::allocate_vertex_buffer() +{ + QueueFamilyIndices indices = find_queue_family_indices(physical_device_, surface_); + std::set set_indices = {indices.graphics_family.value(), + indices.present_family.value(), + indices.transfer_family.value()}; + std::vector arr_indices; + std::vector transfer_index = {indices.transfer_family.value()}; + arr_indices.reserve(set_indices.size()); + for (auto& i : set_indices) + arr_indices.push_back(i); + + + VkBuffer staging_buffer = VK_NULL_HANDLE; + VkDeviceMemory staging_buffer_memory = VK_NULL_HANDLE; + + VkDeviceSize size_buffer = sizeof(vertices[0]) * vertices.size(); + create_buffer(size_buffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, &staging_buffer, transfer_index); + allocate_memory(staging_buffer, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &staging_buffer_memory); + + create_buffer(size_buffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, &vertex_buffer_, arr_indices); + allocate_memory(vertex_buffer_, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &vertex_buffer_memory_); + + VK_CHECK(vkBindBufferMemory(device_, staging_buffer, staging_buffer_memory, 0)); + VK_CHECK(vkBindBufferMemory(device_, vertex_buffer_, vertex_buffer_memory_, 0)); + + void* data; + VK_CHECK(vkMapMemory(device_, staging_buffer_memory, 0, size_buffer, 0, &data)); + memcpy(data, vertices.data(), size_buffer); + vkUnmapMemory(device_, staging_buffer_memory); + + copy_memory(staging_buffer, vertex_buffer_, size_buffer); + + vkFreeMemory(device_, staging_buffer_memory, nullptr); + vkDestroyBuffer(device_, staging_buffer, nullptr); +} + +void RenderEngine::copy_memory(VkBuffer src, VkBuffer dst, VkDeviceSize size) +{ + QueueFamilyIndices indices = find_queue_family_indices(physical_device_, surface_); + VkCommandPool copy_pool; + VkCommandPoolCreateInfo copy_pool_info{}; + copy_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + copy_pool_info.queueFamilyIndex = indices.transfer_family.value(); + copy_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + VK_CHECK(vkCreateCommandPool(device_, ©_pool_info, nullptr, ©_pool)); + + VkCommandBufferAllocateInfo command_buffer_allocate_info{}; + command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_allocate_info.commandPool = copy_pool; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + command_buffer_allocate_info.commandBufferCount = 1; + + VkCommandBuffer copy_buffer; + VK_CHECK(vkAllocateCommandBuffers(device_, &command_buffer_allocate_info, ©_buffer)); + + VkCommandBufferBeginInfo command_buffer_begin_info{}; + command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + VK_CHECK(vkBeginCommandBuffer(copy_buffer, &command_buffer_begin_info)); + + VkBufferCopy buffer_copy{}; + buffer_copy.srcOffset = 0; + buffer_copy.dstOffset = 0; + buffer_copy.size = size; + vkCmdCopyBuffer(copy_buffer, src, dst, 1, &buffer_copy); + + vkEndCommandBuffer(copy_buffer); + + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = ©_buffer; + + vkQueueSubmit(transfer_queue_, 1, &submit_info, VK_NULL_HANDLE); + vkQueueWaitIdle(transfer_queue_); + + vkFreeCommandBuffers(device_, copy_pool, 1, ©_buffer); + vkDestroyCommandPool(device_, copy_pool, nullptr); +} + +void RenderEngine::allocate_command_buffers() +{ + command_buffers_.resize(swapchain_images_.size()); + + VkCommandBufferAllocateInfo command_buffer_allocate_info{}; + command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_allocate_info.commandPool = command_pool_; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + command_buffer_allocate_info.commandBufferCount = static_cast(command_buffers_.size()); + + VK_CHECK(vkAllocateCommandBuffers(device_, &command_buffer_allocate_info, command_buffers_.data())); +} + +void RenderEngine::create_sync_objects() +{ + image_available_semaphores_.resize(swapchain_images_.size()); + render_finished_semaphores_.resize(swapchain_images_.size()); + in_flight_fences_.resize(swapchain_images_.size()); + + VkSemaphoreCreateInfo semaphore_info{}; + semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + VkFenceCreateInfo fence_info{}; + fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; + + for (size_t i = 0; i < swapchain_images_.size(); ++i) + { + VK_CHECK(vkCreateSemaphore(device_, &semaphore_info, nullptr, &image_available_semaphores_[i])); + VK_CHECK(vkCreateSemaphore(device_, &semaphore_info, nullptr, &render_finished_semaphores_[i])); + VK_CHECK(vkCreateFence(device_, &fence_info, nullptr, &in_flight_fences_[i])); + } +} + +void RenderEngine::record_command_buffer(VkCommandBuffer command_buffer, uint32_t image_index) const +{ + VkCommandBufferBeginInfo command_buffer_begin_info{}; + command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + VK_CHECK(vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info)); + + constexpr VkClearValue clear_color = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; + VkRenderPassBeginInfo render_pass_begin_info{}; + render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + render_pass_begin_info.renderPass = render_pass_; + render_pass_begin_info.framebuffer = framebuffers_[image_index]; + render_pass_begin_info.renderArea.offset = {0, 0}; + render_pass_begin_info.renderArea.extent = swapchain_extent_; + render_pass_begin_info.clearValueCount = 1; + render_pass_begin_info.pClearValues = &clear_color; + vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); + + vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_); + + VkBuffer vertex_buffers[] = {vertex_buffer_}; + VkDeviceSize offset[] = {0}; + vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, offset); + + VkViewport viewport; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = static_cast(swapchain_extent_.width); + viewport.height = static_cast(swapchain_extent_.height); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + vkCmdSetViewport(command_buffer, 0, 1, &viewport); + + VkRect2D scissor; + scissor.offset = {0, 0}; + scissor.extent = swapchain_extent_; + vkCmdSetScissor(command_buffer, 0, 1, &scissor); + + vkCmdDraw(command_buffer, static_cast(vertices.size()), 1, 0, 0); + + vkCmdEndRenderPass(command_buffer); + VK_CHECK(vkEndCommandBuffer(command_buffer)); +} + +void RenderEngine::draw_frame() +{ + vkWaitForFences(device_, 1, &in_flight_fences_[current_frame_], VK_TRUE, UINT64_MAX); + vkResetFences(device_, 1, &in_flight_fences_[current_frame_]); + + uint32_t image_index; + vkAcquireNextImageKHR(device_, swapchain_, UINT64_MAX, image_available_semaphores_[current_frame_], VK_NULL_HANDLE, &image_index); + + vkResetCommandBuffer(command_buffers_[current_frame_], 0); + record_command_buffer(command_buffers_[current_frame_], image_index); + + VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffers_[current_frame_]; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = &image_available_semaphores_[current_frame_]; + submit_info.pWaitDstStageMask = &wait_stage; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &render_finished_semaphores_[current_frame_]; + + VK_CHECK(vkQueueSubmit(graphics_queue_, 1, &submit_info, in_flight_fences_[current_frame_])); + + VkPresentInfoKHR present_info{}; + present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + present_info.waitSemaphoreCount = 1; + present_info.pWaitSemaphores = &render_finished_semaphores_[current_frame_]; + present_info.swapchainCount = 1; + present_info.pSwapchains = &swapchain_; + present_info.pImageIndices = &image_index; + present_info.pResults = nullptr; + + vkQueuePresentKHR(present_queue_, &present_info); + + current_frame_ = (current_frame_ + 1) % static_cast(swapchain_images_.size()); +} + +void RenderEngine::create_surface() +{ + VK_CHECK(glfwCreateWindowSurface(instance_, window_, nullptr, &surface_)); +} + +RenderEngine::RenderEngine(CoreInstance& core, GLFWwindow* window, VkPresentModeKHR desired_present_mode): +core_(core), +window_(window) +#ifdef _DEBUG +,debug_messenger_(nullptr) +#endif +{ + create_instance(); + create_surface(); + pick_physical_device(); + create_logical_device(); + create_swapchain(desired_present_mode); + create_image_views(); + create_render_pass(); + create_graphics_pipeline(); + create_framebuffers(); + create_command_pool(); + allocate_vertex_buffer(); + allocate_command_buffers(); + create_sync_objects(); +} + +RenderEngine::~RenderEngine() +{ + vkDeviceWaitIdle(device_); + + if (vertex_buffer_memory_ != VK_NULL_HANDLE) + vkFreeMemory(device_, vertex_buffer_memory_, nullptr); + + if (vertex_buffer_ != VK_NULL_HANDLE) + vkDestroyBuffer(device_, vertex_buffer_, nullptr); + + for (auto& i : image_available_semaphores_) + vkDestroySemaphore(device_, i, nullptr); + + for (auto& i : render_finished_semaphores_) + vkDestroySemaphore(device_, i, nullptr); + + for (auto& i : in_flight_fences_) + vkDestroyFence(device_, i, nullptr); + + if (command_buffers_.empty() == false) + vkFreeCommandBuffers(device_, command_pool_, static_cast(command_buffers_.size()), command_buffers_.data()); + + if (command_pool_ != VK_NULL_HANDLE) + vkDestroyCommandPool(device_, command_pool_, nullptr); + + for (auto& i : framebuffers_) + vkDestroyFramebuffer(device_, i, nullptr); + + if (graphics_pipeline_ != VK_NULL_HANDLE) + vkDestroyPipeline(device_, graphics_pipeline_, nullptr); + + if (pipeline_layout_ != VK_NULL_HANDLE) + vkDestroyPipelineLayout(device_, pipeline_layout_, nullptr); + + if (render_pass_ != VK_NULL_HANDLE) + vkDestroyRenderPass(device_, render_pass_, nullptr); + + for (auto image_view : swapchain_image_views_) + vkDestroyImageView(device_, image_view, nullptr); + swapchain_image_views_.clear(); + + if (swapchain_ != VK_NULL_HANDLE) + vkDestroySwapchainKHR(device_, swapchain_, nullptr); + + if (device_ != VK_NULL_HANDLE) + vkDestroyDevice(device_, nullptr); + + if (surface_ != VK_NULL_HANDLE) + vkDestroySurfaceKHR(instance_, surface_, nullptr); + +#ifdef _DEBUG + if (debug_messenger_ != nullptr && instance_ != nullptr) { + PFN_vkDestroyDebugUtilsMessengerEXT destroyer_messenger = reinterpret_cast(vkGetInstanceProcAddr(instance_, "vkDestroyDebugUtilsMessengerEXT")); + destroyer_messenger(instance_, debug_messenger_, nullptr); + } +#endif + + if (instance_ != VK_NULL_HANDLE) + vkDestroyInstance(instance_, nullptr); + + if (window_ != nullptr) + glfwDestroyWindow(window_); + glfwTerminate(); +} + +void RenderEngine::start() +{ + while (!glfwWindowShouldClose(window_)) + { + glfwPollEvents(); + draw_frame(); + } +} + +void RenderEngine::stop_render() const +{ + if (window_ != nullptr && !glfwWindowShouldClose(window_)) + glfwSetWindowShouldClose(window_, true); +} diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine.h new file mode 100644 index 0000000..cdef903 --- /dev/null +++ b/Core/Core/RenderEngine.h @@ -0,0 +1,126 @@ +#pragma once + +#include +#include +#include +#include + +#define GLFW_INCLUDE_VULKAN +#include + +#include +#include + +#ifdef _DEBUG +#include +#define VK_CHECK(res) assert(res == VK_SUCCESS) +#else +#define VK_CHECK(res) if ((res) != VK_SUCCESS) throw std::runtime_error("Vulkan error: " + std::to_string(res)) +#endif + +class CoreInstance; + +class RenderEngine +{ + struct QueueFamilyIndices + { + std::optional graphics_family; + std::optional present_family; + std::optional transfer_family; + }; + struct SwapchainSupportDetails + { + VkSurfaceCapabilitiesKHR capabilities; + std::vector formats; + std::vector present_modes; + }; + +#pragma region Experemental + struct Vertex + { + glm::vec2 pos; + glm::vec3 color; + static VkVertexInputBindingDescription get_binding_description(); + static std::array get_vertex_attribute_descriptions(); + }; + std::vector vertices = { + {{0.0f, -0.5f}, {1.0f, 0.0f, 0.0f}}, + {{0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}}, + {{-0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}} + }; + VkBuffer vertex_buffer_ = VK_NULL_HANDLE; + VkDeviceMemory vertex_buffer_memory_ = VK_NULL_HANDLE; + uint32_t find_memory_type(uint32_t typeFilter, VkMemoryPropertyFlags properties) const; + void allocate_vertex_buffer(); + void copy_memory(VkBuffer src, VkBuffer dst, VkDeviceSize size); +#pragma endregion + + static const std::vector deviceExtensions; + + int current_frame_ = 0; + + CoreInstance& core_; + GLFWwindow* window_; + VkInstance instance_ = VK_NULL_HANDLE; + VkSurfaceKHR surface_ = VK_NULL_HANDLE; + VkPhysicalDevice physical_device_ = VK_NULL_HANDLE; + VkDevice device_ = VK_NULL_HANDLE; + VkQueue graphics_queue_ = VK_NULL_HANDLE; + VkQueue present_queue_ = VK_NULL_HANDLE; + VkQueue transfer_queue_ = VK_NULL_HANDLE; + VkSwapchainKHR swapchain_ = VK_NULL_HANDLE; + std::vector swapchain_images_; + VkFormat swapchain_image_format_; + VkExtent2D swapchain_extent_; + std::vector swapchain_image_views_; + VkRenderPass render_pass_ = VK_NULL_HANDLE; + VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE; + VkPipeline graphics_pipeline_ = VK_NULL_HANDLE; + std::vector framebuffers_; + VkCommandPool command_pool_ = VK_NULL_HANDLE; + std::vector command_buffers_; + + std::vector image_available_semaphores_, render_finished_semaphores_; + std::vector in_flight_fences_; + +#ifdef _DEBUG + VkResult enable_layer_validation(const VkDebugUtilsMessengerCreateInfoEXT* create_info); + VkDebugUtilsMessengerEXT debug_messenger_; +#endif + SwapchainSupportDetails query_swapchain_details() const; + + static std::vector get_required_extensions(); + static bool is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface); + static bool check_device_extensions_support(VkPhysicalDevice device); + static QueueFamilyIndices find_queue_family_indices(VkPhysicalDevice physical_device, VkSurfaceKHR surface); + static VkSurfaceFormatKHR choose_surface_format(const std::vector& surface_formats); + static VkPresentModeKHR choose_present_mode(const std::vector& present_modes, VkPresentModeKHR desired_present_mode); + static VkExtent2D choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window); + VkShaderModule create_shader_module(const std::string& code) const; + void create_buffer(VkDeviceSize size, VkBufferUsageFlags usage, + VkBuffer* buffer, const std::vector& queue_families); + void allocate_memory(VkBuffer buffer, VkMemoryPropertyFlags property, VkDeviceMemory* device_memory); + + void create_instance(); + void create_surface(); + void pick_physical_device(); + void create_logical_device(); + void create_swapchain(VkPresentModeKHR desired_present_mode); + void create_image_views(); + void create_render_pass(); + void create_graphics_pipeline(); + void create_framebuffers(); + void create_command_pool(); + void allocate_command_buffers(); + void create_sync_objects(); + + void record_command_buffer(VkCommandBuffer command_buffer, uint32_t image_index) const; + void draw_frame(); +public: + // Can throw the exception + RenderEngine(CoreInstance& core, GLFWwindow* window, VkPresentModeKHR desired_present_mode = VK_PRESENT_MODE_MAILBOX_KHR); + ~RenderEngine(); + + void start(); + void stop_render() const; +}; \ No newline at end of file diff --git a/Core/Core/Windows.cpp b/Core/Core/Windows/WindowsCalls.cpp similarity index 95% rename from Core/Core/Windows.cpp rename to Core/Core/Windows/WindowsCalls.cpp index 41ab21c..ad05a22 100644 --- a/Core/Core/Windows.cpp +++ b/Core/Core/Windows/WindowsCalls.cpp @@ -1,6 +1,6 @@ #ifdef _WIN32 -#include "SystemCalls.h" +#include "../SystemCalls.h" #include @@ -38,7 +38,7 @@ double System::getMemorySize() { memStatus.dwLength = sizeof(memStatus); GlobalMemoryStatusEx(&memStatus); - return memStatus.ullTotalPhys / 1024 / 1024; + return static_cast(memStatus.ullTotalPhys) / 1024. / 1024.; } void* System::InitModule(const char* ModuleName, CoreCallBacks* callbacks) { diff --git a/Core/Game/GameInstance.cpp b/Core/Game/GameInstance.cpp index 7442993..43c5f37 100644 --- a/Core/Game/GameInstance.cpp +++ b/Core/Game/GameInstance.cpp @@ -63,7 +63,13 @@ void GameInstance::start() } } -void GameInstance::quit() +void GameInstance::stop() { is_running = false; } + +void GameInstance::quit() +{ + stop(); + core.quit(); +} diff --git a/Core/Game/GameInstance.h b/Core/Game/GameInstance.h index 6fc0fc3..3da336a 100644 --- a/Core/Game/GameInstance.h +++ b/Core/Game/GameInstance.h @@ -16,11 +16,8 @@ class GameInstance std::atomic is_running = true; - // Create a window - // Render - // Pull events void start(); - + void stop(); public: void quit(); diff --git a/Core/Game/SaveMap/SaveMap.cpp b/Core/Game/SaveMap/SaveMap.cpp index f6df842..93f1417 100644 --- a/Core/Game/SaveMap/SaveMap.cpp +++ b/Core/Game/SaveMap/SaveMap.cpp @@ -66,7 +66,11 @@ SaveMap::SaveMap(const std::string& json_data) size_t begin = json_data.find(':', i) + 2; size_t end = i = json_data.find('\"', begin); i++; - std::string value = json_data.substr(begin, end - begin); + std::string value; + if (begin != end) + value = json_data.substr(begin, end - begin); + else + value = ""; save_string[name.c_str() + 1] = value; } else if (name[0] == 'o') { @@ -147,12 +151,16 @@ SaveMap::SaveMap(const std::string& json_data) continue; std::vector& vector_strings = save_vector_strings[key]; - size_t j = 2; + size_t j = 0; while (j < arr_data.length()) { - size_t begin = j; - size_t end = j = arr_data.find('\"', begin + 1); - std::string value = arr_data.substr(begin, end - begin); + size_t begin = arr_data.find('\"', j) + 1; + size_t end = j = arr_data.find('\"', begin); + std::string value; + if (begin != end) + value = arr_data.substr(begin, end - begin); + else + value = ""; vector_strings.push_back(value); j += 3; } diff --git a/RenderModule/CMakeLists.txt b/RenderModule/CMakeLists.txt deleted file mode 100644 index 7eda801..0000000 --- a/RenderModule/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -find_package(Vulkan REQUIRED) - -file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp") -add_library(RenderModule SHARED ${SRC}) - -target_compile_features(RenderModule PRIVATE cxx_std_17) - -target_include_directories(RenderModule - PRIVATE - ${PROJECT_SOURCE_DIR}/ModuleLib - ${PROJECT_SOURCE_DIR}/Core - ${PROJECT_SOURCE_DIR}/FastRTTI - ${PROJECT_SOURCE_DIR}/Delegate - ${PROJECT_SOURCE_DIR}/glfw/Include - ${Vulkan_INCLUDE_DIRS} -) - -target_link_libraries(RenderModule PRIVATE - ModuleLib - FastRTTI - glfw - Vulkan::Vulkan -) \ No newline at end of file diff --git a/RenderModule/RenderEngine.cpp b/RenderModule/RenderEngine.cpp deleted file mode 100644 index ec07447..0000000 --- a/RenderModule/RenderEngine.cpp +++ /dev/null @@ -1,150 +0,0 @@ -#include "RenderEngine.h" - -#include -#include -#include - -#include "Core/CoreInstance.h" - -PROTECTION_FROM_GB(RenderEngine) - -#ifdef _DEBUG -//#include "Log/Log.h" -#include -#define VK_CHECK(res) assert(res == VK_SUCCESS) - -static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, - void* pUserData) { - - std::string msg = "validation layer: "; - msg += pCallbackData->pMessage; - //Log(msg); - - return VK_FALSE; -} - -VkResult RenderEngine::enable_layer_validation(VkInstance instance, VkDebugUtilsMessengerCreateInfoEXT* create_info) -{ - PFN_vkCreateDebugUtilsMessengerEXT debug_creator = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT")); - return debug_creator(instance, create_info, nullptr, &debug_messenger_); -} -#else -#define VK_CHECK(res) if ((res) != VK_SUCCESS) throw std::runtime_error("Vulkan error: " + std::to_string(res)) -#endif - -std::vector RenderEngine::get_required_extensions() -{ - uint32_t extensions_count = 0; - const char** glfw_extension = glfwGetRequiredInstanceExtensions(&extensions_count); - std::vector extensions(glfw_extension, glfw_extension + extensions_count); - -#ifdef _DEBUG - extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); -#endif - return extensions; -} - -RenderEngine::RenderEngine() : window(nullptr) -#ifdef _DEBUG -, debug_messenger_(nullptr) -#endif -{ - onStop.bind(this, &RenderEngine::stop_render); - - if (glfwInit() == GLFW_FALSE) - throw std::runtime_error("Fail init glfw"); - - { - std::vector extensions = get_required_extensions(); - std::vector layers = { -#ifdef _DEBUG - "VK_LAYER_KHRONOS_validation" -#endif - }; - - VkApplicationInfo app_info{}; - app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - app_info.apiVersion = VK_API_VERSION_1_0; - app_info.applicationVersion = VK_MAKE_VERSION(0, 0, 0); - app_info.pApplicationName = "UwU Engine"; - app_info.pEngineName = "UwU Engine"; - app_info.engineVersion = VK_MAKE_VERSION(0, 0, 0); - - - VkInstanceCreateInfo instance_create_info{}; - instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - instance_create_info.pApplicationInfo = &app_info; - instance_create_info.enabledExtensionCount = extensions.size(); - instance_create_info.ppEnabledExtensionNames = extensions.data(); - instance_create_info.enabledLayerCount = layers.size(); - instance_create_info.ppEnabledLayerNames = layers.data(); -#ifdef _DEBUG - VkDebugUtilsMessengerCreateInfoEXT debug_messenger_create_info{}; - debug_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - debug_messenger_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; - debug_messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; - debug_messenger_create_info.pfnUserCallback = &debugCallback; - instance_create_info.pNext = &debug_messenger_create_info; -#endif - VK_CHECK(vkCreateInstance(&instance_create_info, nullptr, &instance_)); -#ifdef _DEBUG - VK_CHECK(enable_layer_validation(instance_, &debug_messenger_create_info)); -#endif - } - - { - uint32_t device_count = 0; - std::vector devices; - VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, nullptr)); - VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, devices.data())); - - for (const auto& device : devices) - { - VkPhysicalDeviceProperties device_properties; - vkGetPhysicalDeviceProperties(device, &device_properties); - } - } -} - -RenderEngine::~RenderEngine() -{ -#ifdef _DEBUG - if (debug_messenger_ != nullptr && instance_ != nullptr) { - PFN_vkDestroyDebugUtilsMessengerEXT destroyer_messenger = reinterpret_cast(vkGetInstanceProcAddr(instance_, "vkDestroyDebugUtilsMessengerEXT")); - destroyer_messenger(instance_, debug_messenger_, nullptr); - } -#endif - - if (instance_ != nullptr) - vkDestroyInstance(instance_, nullptr); - - if (window != nullptr) - glfwDestroyWindow(window); - glfwTerminate(); -} - -void RenderEngine::start() -{ - window = glfwCreateWindow(640, 480, "UwU Engine", nullptr, nullptr); - if (!window) - { - glfwTerminate(); - throw std::runtime_error("Fail create window"); - } - - while (!glfwWindowShouldClose(window)) - { - glfwSwapBuffers(window); - glfwPollEvents(); - } - QuitGame(); -} - -void RenderEngine::stop_render() -{ - if (window != nullptr && !glfwWindowShouldClose(window)) - glfwSetWindowShouldClose(window, true); -} diff --git a/RenderModule/RenderEngine.h b/RenderModule/RenderEngine.h deleted file mode 100644 index 3551b85..0000000 --- a/RenderModule/RenderEngine.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#define GLFW_INCLUDE_VULKAN -#include "GLFW/glfw3.h" - -#include "ModuleInstance.h" - -#include - -template -class Delegate; - -class RenderEngine : public ModuleInstance -{ - GLFWwindow* window; - VkInstance instance_; - -#ifdef _DEBUG - VkResult enable_layer_validation(VkInstance instance, VkDebugUtilsMessengerCreateInfoEXT* create_info); - VkDebugUtilsMessengerEXT debug_messenger_; -#endif - - static std::vector get_required_extensions(); - - void stop_render(); -public: - RenderEngine(); - ~RenderEngine() override; - - void start() override; -}; \ No newline at end of file diff --git a/TestGame/CMakeLists.txt b/TestGame/CMakeLists.txt index bd5b200..3b3abba 100644 --- a/TestGame/CMakeLists.txt +++ b/TestGame/CMakeLists.txt @@ -2,7 +2,7 @@ set(GAME_NAME TestGame) set(CMAKE_CXX_STANDARD 20) -file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp" "*.res" "*.world" "*.conf") +file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp" "*.res" "*.world" "*.conf" "*.frag" "*.vert") add_executable(${GAME_NAME} ${SRC}) target_link_libraries(${GAME_NAME} PRIVATE Core) @@ -45,3 +45,28 @@ add_custom_command( ${OUTPUT_PATH}/Resources COMMENT "Copying Resources directory" ) + +add_custom_command( + TARGET ${GAME_NAME} + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTPUT_PATH}/Shaders + COMMENT "Creating Shaders directory" +) + +add_custom_command( + TARGET ${GAME_NAME} + POST_BUILD + COMMAND $ENV{VULKAN_SDK}/Bin/glslc.exe + ${CMAKE_CURRENT_SOURCE_DIR}/Shaders/vertex.vert + -o ${OUTPUT_PATH}/Shaders/vertex.spv + COMMENT "Building vertex shader" +) + +add_custom_command( + TARGET ${GAME_NAME} + POST_BUILD + COMMAND $ENV{VULKAN_SDK}/Bin/glslc.exe + ${CMAKE_CURRENT_SOURCE_DIR}/Shaders/fragment.frag + -o ${OUTPUT_PATH}/Shaders/fragment.spv + COMMENT "Building fragment shader" +) diff --git a/TestGame/Shaders/fragment.frag b/TestGame/Shaders/fragment.frag new file mode 100644 index 0000000..e948fd6 --- /dev/null +++ b/TestGame/Shaders/fragment.frag @@ -0,0 +1,8 @@ +#version 450 + +layout(location = 0) in vec3 fragColor; +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); +} \ No newline at end of file diff --git a/TestGame/Shaders/vertex.vert b/TestGame/Shaders/vertex.vert new file mode 100644 index 0000000..92ceacd --- /dev/null +++ b/TestGame/Shaders/vertex.vert @@ -0,0 +1,12 @@ +#version 450 + +layout(location = 0) in vec2 inPosition; +layout(location = 1) in vec3 inColor; + +layout(location = 0) out vec3 fragColor; + +void main() +{ + gl_Position = vec4(inPosition, 0.0, 1.0); + fragColor = inColor; +} \ No newline at end of file diff --git a/TestGame/main_config.conf b/TestGame/main_config.conf index c99154d..a51e392 100644 --- a/TestGame/main_config.conf +++ b/TestGame/main_config.conf @@ -1 +1 @@ -{"Class name":"MainConfig","dmin_memory_size":"4096.0","imin_CPU_count":"1","sgame_name":"Test Game","sbase_world":"TestWorld","vsmodules_names":["RenderModule"]} \ No newline at end of file +{"Class name":"MainConfig","dmin_memory_size":"4096.0","imin_CPU_count":"1","sgame_name":"Test Game","sbase_world":"TestWorld","vsmodules_names":[]} \ No newline at end of file