2025-04-18 06:18:45 +02:00
|
|
|
#include <vulkan/vulkan.hpp>
|
|
|
|
#include <GLFW/glfw3.h>
|
|
|
|
#include <print>
|
2025-04-28 20:52:26 +02:00
|
|
|
#include <filesystem>
|
2025-04-18 06:18:45 +02:00
|
|
|
#include <vector>
|
|
|
|
#include <fstream>
|
2025-04-24 04:13:58 +02:00
|
|
|
#include <glm/glm.hpp>
|
2025-05-26 22:40:20 +02:00
|
|
|
#include <atomic>
|
|
|
|
#include <thread>
|
2025-04-24 04:13:58 +02:00
|
|
|
|
2025-04-28 20:52:26 +02:00
|
|
|
bool skip_rendering = false;
|
|
|
|
vk::SurfaceFormatKHR format;
|
|
|
|
vk::Extent2D framebuffer_extension;
|
|
|
|
|
2025-05-24 22:26:40 +02:00
|
|
|
std::vector<glm::vec2> identity_mat_2d = {{1, 0}, {0,1}};
|
|
|
|
|
2025-04-24 04:13:58 +02:00
|
|
|
struct vertex
|
|
|
|
{
|
|
|
|
glm::vec2 position;
|
|
|
|
glm::vec3 color;
|
|
|
|
};
|
2025-04-18 06:18:45 +02:00
|
|
|
|
2025-05-26 22:40:20 +02:00
|
|
|
struct bounding_box
|
|
|
|
{
|
|
|
|
float x;
|
|
|
|
float y;
|
|
|
|
float width;
|
|
|
|
float height;
|
|
|
|
};
|
|
|
|
|
|
|
|
bounding_box player;
|
|
|
|
float velocityX = 1.0f;
|
|
|
|
float velocityY = 0.50f;
|
|
|
|
std::atomic_bool thread = true;
|
|
|
|
|
2025-04-18 06:18:45 +02:00
|
|
|
std::vector<char> read_file(const char *filename)
|
|
|
|
{
|
2025-04-21 21:40:30 +02:00
|
|
|
std::ifstream file(filename, std::ios::binary);
|
2025-04-18 06:18:45 +02:00
|
|
|
file.seekg(0,std::ios::end);
|
|
|
|
std::streampos length = file.tellg();
|
|
|
|
file.seekg(0,std::ios::beg);
|
|
|
|
std::vector<char> buffer(length);
|
|
|
|
file.read(&buffer[0],length);
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
GLFWwindow *create_window(int width, int height, const char *title)
|
|
|
|
{
|
|
|
|
glfwInit();
|
|
|
|
|
|
|
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
|
|
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
|
|
|
|
|
|
|
GLFWwindow *window = glfwCreateWindow(width, height, title, nullptr, nullptr);
|
|
|
|
|
|
|
|
if (!window)
|
|
|
|
{
|
|
|
|
std::println("GLFW window creation failed!");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return window;
|
|
|
|
}
|
|
|
|
|
2025-04-26 05:52:05 +02:00
|
|
|
vk::PhysicalDevice select_physical_device(std::vector<vk::PhysicalDevice> devices)
|
|
|
|
{
|
|
|
|
if (devices.size() == 1)
|
|
|
|
return devices[0];
|
|
|
|
|
|
|
|
vk::PhysicalDevice selected_physical_device;
|
|
|
|
for (auto device: devices)
|
|
|
|
{
|
|
|
|
vk::PhysicalDeviceProperties device_propierties = device.getProperties();
|
|
|
|
if (device_propierties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu)
|
|
|
|
{
|
|
|
|
selected_physical_device = device;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
selected_physical_device = device;
|
|
|
|
}
|
|
|
|
return selected_physical_device;
|
|
|
|
}
|
2025-04-22 02:46:51 +02:00
|
|
|
|
2025-04-28 20:52:26 +02:00
|
|
|
vk::SwapchainKHR create_swapchain(vk::PhysicalDevice phy_device, vk::SurfaceKHR surface, GLFWwindow *window, vk::Device device)
|
|
|
|
{
|
|
|
|
vk::SurfaceCapabilitiesKHR surface_capabilities = phy_device.getSurfaceCapabilitiesKHR(surface);
|
|
|
|
int width = 0;
|
|
|
|
int height = 0;
|
|
|
|
if (surface_capabilities.currentExtent.height == UINT32_MAX || surface_capabilities.currentExtent.width == UINT32_MAX)
|
|
|
|
{
|
|
|
|
glfwGetFramebufferSize(window, &width, &height);
|
|
|
|
width = std::clamp((uint32_t)width, surface_capabilities.minImageExtent.width, surface_capabilities.maxImageExtent.width);
|
|
|
|
height = std::clamp((uint32_t)height, surface_capabilities.minImageExtent.height, surface_capabilities.maxImageExtent.height);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
width = surface_capabilities.currentExtent.width;
|
|
|
|
height = surface_capabilities.currentExtent.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (width == 0 && height == 0)
|
|
|
|
{
|
|
|
|
skip_rendering = true;
|
|
|
|
}
|
|
|
|
framebuffer_extension = vk::Extent2D(width, height);
|
|
|
|
std::println("Extents width {} height {}", width, height);
|
|
|
|
|
|
|
|
std::vector<vk::SurfaceFormatKHR> surface_formats = phy_device.getSurfaceFormatsKHR(surface);
|
|
|
|
|
|
|
|
for (auto form: surface_formats)
|
|
|
|
{
|
|
|
|
if (form.format == vk::Format::eB8G8R8A8Srgb && form.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear)
|
|
|
|
{
|
|
|
|
format = form;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<vk::PresentModeKHR> present_modes = phy_device.getSurfacePresentModesKHR(surface);
|
|
|
|
vk::PresentModeKHR mode = vk::PresentModeKHR::eFifo;
|
|
|
|
if (std::find(present_modes.begin(), present_modes.end(), vk::PresentModeKHR::eFifoRelaxed) != present_modes.end())
|
|
|
|
{
|
|
|
|
mode = vk::PresentModeKHR::eFifoRelaxed;
|
|
|
|
std::println("Selected relaxed FIFO");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::println("Selected FIFO");
|
|
|
|
}
|
|
|
|
|
|
|
|
vk::SwapchainCreateInfoKHR swapchain_info = vk::SwapchainCreateInfoKHR(vk::SwapchainCreateFlagsKHR(), surface, 2, format.format, format.colorSpace, framebuffer_extension,
|
|
|
|
1, vk::ImageUsageFlagBits::eColorAttachment, vk::SharingMode::eExclusive);
|
|
|
|
swapchain_info.preTransform = surface_capabilities.currentTransform;
|
|
|
|
swapchain_info.presentMode = mode;
|
|
|
|
swapchain_info.clipped = VK_TRUE;
|
|
|
|
swapchain_info.oldSwapchain = vk::SwapchainKHR(nullptr);
|
|
|
|
swapchain_info.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque;
|
|
|
|
|
|
|
|
|
|
|
|
return device.createSwapchainKHR(swapchain_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
void compile_shader(const char *filename)
|
|
|
|
{
|
|
|
|
system(std::format("glslc {} -o {}.spv", filename, filename).c_str());
|
|
|
|
}
|
|
|
|
|
2025-05-24 22:26:40 +02:00
|
|
|
std::vector<vertex> convert_quad_to_triangles(std::vector<vertex> vertices)
|
|
|
|
{
|
|
|
|
const vertex end_vertex = vertices[3];
|
|
|
|
vertices.pop_back();
|
|
|
|
vertices.push_back(vertices[0]);
|
|
|
|
vertices.push_back(vertices[2]);
|
|
|
|
vertices.push_back(end_vertex);
|
|
|
|
return vertices;
|
|
|
|
}
|
|
|
|
|
|
|
|
glm::mat2 rotate(float angle)
|
|
|
|
{
|
|
|
|
float c = glm::cos(glm::radians(angle));
|
|
|
|
float s = glm::sin(glm::radians(angle));
|
|
|
|
glm::mat2 transform({c, s}, {-s, c});
|
|
|
|
return transform;
|
|
|
|
}
|
|
|
|
|
|
|
|
glm::mat2 scale(glm::vec2 scale)
|
|
|
|
{
|
|
|
|
glm::mat2 transform({scale.x, 0.0f}, {0.0f, scale.y});
|
|
|
|
return transform;
|
|
|
|
}
|
|
|
|
|
|
|
|
glm::mat3 move(glm::vec2 pos)
|
|
|
|
{
|
|
|
|
glm::mat3 transform({1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {pos.x, pos.y, 1.0f});
|
|
|
|
return transform;
|
|
|
|
}
|
|
|
|
|
2025-05-26 22:40:20 +02:00
|
|
|
void simple_physics()
|
|
|
|
{
|
|
|
|
while (thread.load() == true)
|
|
|
|
{
|
|
|
|
bool collision_x = player.x + player.width / 2 >= 1.0f || player.x - player.width / 2 <= -1.0f;
|
|
|
|
bool collision_y = player.y + player.height / 2 >=1.0f || player.y - player.height / 2 <= -1.0f;
|
|
|
|
if (collision_x)
|
|
|
|
velocityX = -velocityX;
|
|
|
|
else if (collision_y)
|
|
|
|
velocityY = -velocityY;
|
|
|
|
player.x = player.x + (velocityX * 0.002f);
|
|
|
|
player.y = player.y + (velocityY * 0.002f);
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(2));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void simple_physics_step(float t)
|
|
|
|
{
|
|
|
|
bool collision_x = player.x + player.width / 2 >= 1.0f || player.x - player.width / 2 <= -1.0f;
|
|
|
|
bool collision_y = player.y + player.height / 2 >=1.0f || player.y - player.height / 2 <= -1.0f;
|
|
|
|
if (collision_x)
|
|
|
|
velocityX = -velocityX;
|
|
|
|
else if (collision_y)
|
|
|
|
velocityY = -velocityY;
|
|
|
|
player.x = player.x + (velocityX * t);
|
|
|
|
player.y = player.y + (velocityY * t);
|
|
|
|
}
|
|
|
|
|
2025-04-18 06:18:45 +02:00
|
|
|
int main()
|
|
|
|
{
|
2025-05-26 22:40:20 +02:00
|
|
|
using clock = std::chrono::system_clock;
|
|
|
|
using ms = std::chrono::duration<double, std::milli>;
|
2025-04-22 02:46:51 +02:00
|
|
|
GLFWwindow *window = create_window(1000, 800, "hello");
|
2025-04-18 06:18:45 +02:00
|
|
|
|
|
|
|
if (!window)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
vk::ApplicationInfo appinfo = vk::ApplicationInfo("Test_vk", VK_MAKE_VERSION(0,1,0), NULL, VK_MAKE_VERSION(0,1,0), VK_API_VERSION_1_4);
|
|
|
|
|
|
|
|
uint32_t extension_count = 0;
|
|
|
|
const char **glfwextensions = glfwGetRequiredInstanceExtensions(&extension_count);
|
|
|
|
std::println("GLFW requested extensions:");
|
|
|
|
std::vector<const char *> extensions;
|
|
|
|
std::vector<const char *> layers;
|
|
|
|
for (int i = 0; i < extension_count;i++)
|
|
|
|
{
|
|
|
|
extensions.push_back(glfwextensions[i]);
|
|
|
|
std::println("{}", glfwextensions[i]);
|
|
|
|
}
|
|
|
|
#ifdef __APPLE__
|
|
|
|
extensions.push_back("VK_KHR_portability_enumeration");
|
|
|
|
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); //Apple silicon extensions
|
|
|
|
#endif
|
2025-04-24 04:13:58 +02:00
|
|
|
#ifndef NDEBUG
|
|
|
|
layers.push_back("VK_LAYER_KHRONOS_validation");
|
|
|
|
#endif
|
2025-04-18 06:18:45 +02:00
|
|
|
|
|
|
|
vk::InstanceCreateInfo createinfo = vk::InstanceCreateInfo(
|
|
|
|
vk::InstanceCreateFlags(VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR),
|
|
|
|
&appinfo,layers.size(), layers.data(),
|
|
|
|
extensions.size(), extensions.data());
|
|
|
|
vk::Instance instance = vk::createInstance(createinfo);
|
|
|
|
|
2025-04-26 05:52:05 +02:00
|
|
|
std::vector<vk::PhysicalDevice> devices = instance.enumeratePhysicalDevices();
|
|
|
|
vk::PhysicalDevice selected_physical_device = select_physical_device(devices);
|
2025-04-18 06:18:45 +02:00
|
|
|
|
|
|
|
std::vector<vk::QueueFamilyProperties> queue_families = selected_physical_device.getQueueFamilyProperties();
|
|
|
|
|
|
|
|
uint32_t graphics_queue_index = 0;
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < queue_families.size(); i++)
|
|
|
|
{
|
|
|
|
if (queue_families[i].queueFlags & vk::QueueFlagBits::eGraphics)
|
|
|
|
{
|
|
|
|
graphics_queue_index = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
float queue_priority = 1.0f;
|
|
|
|
vk::DeviceQueueCreateInfo queue_info = vk::DeviceQueueCreateInfo(vk::DeviceQueueCreateFlags(), graphics_queue_index, 1, &queue_priority);
|
|
|
|
|
2025-04-24 04:13:58 +02:00
|
|
|
std::vector<const char *> device_extensions;
|
2025-04-18 06:18:45 +02:00
|
|
|
|
2025-04-24 04:13:58 +02:00
|
|
|
device_extensions.push_back("VK_KHR_swapchain");
|
|
|
|
#ifdef __APPLE__
|
|
|
|
device_extensions.push_back("VK_KHR_portability_subset");
|
|
|
|
#endif
|
2025-04-18 06:18:45 +02:00
|
|
|
vk::PhysicalDeviceFeatures device_features = vk::PhysicalDeviceFeatures();
|
|
|
|
|
2025-04-24 04:13:58 +02:00
|
|
|
vk::DeviceCreateInfo device_info = vk::DeviceCreateInfo(vk::DeviceCreateFlags(), 1, &queue_info, 0, nullptr, device_extensions.size(), device_extensions.data(), &device_features);
|
2025-04-18 06:18:45 +02:00
|
|
|
|
|
|
|
vk::Device device = selected_physical_device.createDevice(device_info);
|
|
|
|
|
2025-04-22 02:46:51 +02:00
|
|
|
vk::Queue graphics_queue = device.getQueue(graphics_queue_index, 0);
|
|
|
|
|
2025-04-18 06:18:45 +02:00
|
|
|
VkSurfaceKHR raw_surface;
|
|
|
|
glfwCreateWindowSurface(instance, window, nullptr, &raw_surface);
|
|
|
|
vk::SurfaceKHR surface = raw_surface;
|
|
|
|
|
|
|
|
VkBool32 surface_supported = selected_physical_device.getSurfaceSupportKHR(graphics_queue_index, surface);
|
|
|
|
|
|
|
|
if (surface_supported == VK_TRUE)
|
|
|
|
std::println("Surface supported!");
|
|
|
|
else
|
|
|
|
std::println("Surface unsupported!");
|
|
|
|
|
|
|
|
|
2025-04-28 20:52:26 +02:00
|
|
|
vk::SwapchainKHR swapchain = create_swapchain(selected_physical_device, surface, window, device);
|
|
|
|
|
2025-04-18 06:18:45 +02:00
|
|
|
std::vector<vk::Image> images = device.getSwapchainImagesKHR(swapchain);
|
|
|
|
std::println("Got {} images from swapchain", images.size());
|
|
|
|
|
|
|
|
std::vector<vk::ImageView> image_views;
|
|
|
|
for (auto &image: images)
|
|
|
|
{
|
|
|
|
vk::ImageViewCreateInfo image_view_info = {};
|
|
|
|
image_view_info.image = image;
|
|
|
|
image_view_info.viewType = vk::ImageViewType::e2D;
|
|
|
|
image_view_info.format = format.format;
|
|
|
|
image_view_info.components.r = vk::ComponentSwizzle::eIdentity;
|
|
|
|
image_view_info.components.g = vk::ComponentSwizzle::eIdentity;
|
|
|
|
image_view_info.components.b = vk::ComponentSwizzle::eIdentity;
|
|
|
|
image_view_info.components.a = vk::ComponentSwizzle::eIdentity;
|
|
|
|
image_view_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
|
|
|
|
image_view_info.subresourceRange.baseMipLevel = 0;
|
|
|
|
image_view_info.subresourceRange.levelCount = 1;
|
|
|
|
image_view_info.subresourceRange.baseArrayLayer = 0;
|
|
|
|
image_view_info.subresourceRange.layerCount = 1;
|
|
|
|
|
|
|
|
image_views.push_back(device.createImageView(image_view_info));
|
|
|
|
}
|
2025-04-28 20:52:26 +02:00
|
|
|
if (!std::filesystem::exists("../shaders/vertex.vert.spv") && !std::filesystem::exists("../shaders/fragment.frag.spv"))
|
|
|
|
{
|
|
|
|
std::println("Compiling shaders");
|
|
|
|
compile_shader("../shaders/vertex.vert");
|
|
|
|
compile_shader("../shaders/fragment.frag");
|
|
|
|
std::println("Shaders compiled");
|
|
|
|
}
|
|
|
|
std::vector<char> vertex_shader = read_file("../shaders/vertex.vert.spv");
|
|
|
|
std::vector<char> fragment_shader = read_file("../shaders/fragment.frag.spv");
|
2025-04-21 21:40:30 +02:00
|
|
|
|
|
|
|
vk::ShaderModuleCreateInfo vertex_shader_info = vk::ShaderModuleCreateInfo(vk::ShaderModuleCreateFlags(), vertex_shader.size());
|
|
|
|
vertex_shader_info.pCode = (const uint32_t*)(vertex_shader.data());
|
|
|
|
|
|
|
|
vk::ShaderModuleCreateInfo fragment_shader_info = vk::ShaderModuleCreateInfo(vk::ShaderModuleCreateFlags(), fragment_shader.size());
|
|
|
|
fragment_shader_info.pCode = (const uint32_t*)(fragment_shader.data());
|
|
|
|
|
|
|
|
vk::ShaderModule vertex_module = device.createShaderModule(vertex_shader_info);
|
|
|
|
vk::ShaderModule fragment_module = device.createShaderModule(fragment_shader_info);
|
|
|
|
|
|
|
|
vk::PipelineShaderStageCreateInfo vertex_stage_info = {};
|
|
|
|
vertex_stage_info.stage = vk::ShaderStageFlagBits::eVertex;
|
|
|
|
vertex_stage_info.module = vertex_module;
|
|
|
|
vertex_stage_info.pName = "main";
|
|
|
|
|
|
|
|
vk::PipelineShaderStageCreateInfo fragment_stage_info = {};
|
|
|
|
fragment_stage_info.stage = vk::ShaderStageFlagBits::eFragment;
|
|
|
|
fragment_stage_info.module = fragment_module;
|
|
|
|
fragment_stage_info.pName = "main";
|
|
|
|
|
|
|
|
std::vector<vk::PipelineShaderStageCreateInfo> pipeline_shaders = {vertex_stage_info, fragment_stage_info};
|
|
|
|
|
2025-04-24 04:13:58 +02:00
|
|
|
vk::VertexInputBindingDescription binding_description = {};
|
|
|
|
binding_description.binding = 0;
|
|
|
|
binding_description.stride = sizeof(vertex);
|
|
|
|
binding_description.inputRate = vk::VertexInputRate::eVertex;
|
|
|
|
|
|
|
|
vk::VertexInputAttributeDescription att_description_pos = {};
|
|
|
|
att_description_pos.binding = 0;
|
|
|
|
att_description_pos.location = 0;
|
|
|
|
att_description_pos.format = vk::Format::eR32G32Sfloat;
|
|
|
|
att_description_pos.offset = offsetof(vertex, position);
|
|
|
|
|
|
|
|
vk::VertexInputAttributeDescription att_description_color = {};
|
|
|
|
att_description_color.binding = 0;
|
|
|
|
att_description_color.location = 1;
|
|
|
|
att_description_color.format = vk::Format::eR32G32B32Sfloat;
|
|
|
|
att_description_color.offset = offsetof(vertex, color);
|
|
|
|
|
|
|
|
std::vector<vk::VertexInputAttributeDescription> att_descriptions = {att_description_pos, att_description_color};
|
2025-04-21 21:40:30 +02:00
|
|
|
vk::PipelineVertexInputStateCreateInfo vertex_input_info = {};
|
2025-04-24 04:13:58 +02:00
|
|
|
vertex_input_info.vertexAttributeDescriptionCount = 2;
|
|
|
|
vertex_input_info.vertexBindingDescriptionCount = 1;
|
|
|
|
vertex_input_info.pVertexBindingDescriptions = &binding_description;
|
|
|
|
vertex_input_info.pVertexAttributeDescriptions = att_descriptions.data();
|
|
|
|
|
|
|
|
|
2025-04-21 21:40:30 +02:00
|
|
|
vk::PipelineInputAssemblyStateCreateInfo input_assembly_info = vk::PipelineInputAssemblyStateCreateInfo(vk::PipelineInputAssemblyStateCreateFlags(),
|
2025-05-24 22:26:40 +02:00
|
|
|
vk::PrimitiveTopology::eTriangleList, VK_FALSE);
|
2025-04-21 21:40:30 +02:00
|
|
|
vk::Viewport viewport = vk::Viewport(0.0f, 0.0f,
|
|
|
|
framebuffer_extension.width, framebuffer_extension.height,
|
|
|
|
0.0f, 1.0f);
|
|
|
|
vk::Rect2D scissor;
|
|
|
|
scissor.setOffset({0, 0});
|
|
|
|
scissor.extent = framebuffer_extension;
|
|
|
|
|
|
|
|
vk::PipelineViewportStateCreateInfo viewport_info = vk::PipelineViewportStateCreateInfo(vk::PipelineViewportStateCreateFlags(),
|
|
|
|
1, &viewport, 1, &scissor);
|
|
|
|
vk::PipelineRasterizationStateCreateInfo raster_info = {};
|
|
|
|
raster_info.depthClampEnable = VK_FALSE;
|
|
|
|
raster_info.polygonMode = vk::PolygonMode::eFill;
|
|
|
|
raster_info.lineWidth = 1.0f;
|
2025-04-22 02:46:51 +02:00
|
|
|
raster_info.cullMode = vk::CullModeFlagBits::eNone;
|
2025-04-21 21:40:30 +02:00
|
|
|
raster_info.frontFace = vk::FrontFace::eClockwise;
|
|
|
|
raster_info.depthBiasEnable = VK_FALSE;
|
|
|
|
|
|
|
|
vk::PipelineMultisampleStateCreateInfo multisampling_info = {};
|
|
|
|
multisampling_info.sampleShadingEnable = VK_FALSE;
|
|
|
|
multisampling_info.rasterizationSamples = vk::SampleCountFlagBits::e1;
|
|
|
|
|
|
|
|
vk::PipelineColorBlendAttachmentState color_blend_attachment = vk::PipelineColorBlendAttachmentState(VK_FALSE);
|
|
|
|
vk::PipelineColorBlendStateCreateInfo color_blend_info = {};
|
2025-04-22 02:46:51 +02:00
|
|
|
color_blend_attachment.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA;
|
2025-04-21 21:40:30 +02:00
|
|
|
color_blend_info.logicOpEnable = VK_FALSE;
|
|
|
|
color_blend_info.attachmentCount = 1;
|
|
|
|
color_blend_info.pAttachments = &color_blend_attachment;
|
|
|
|
|
|
|
|
vk::PipelineLayoutCreateInfo layout_info = {};
|
|
|
|
vk::PipelineLayout pipeline_layout = device.createPipelineLayout(layout_info);
|
|
|
|
|
|
|
|
|
|
|
|
vk::AttachmentDescription color_attachment = vk::AttachmentDescription(vk::AttachmentDescriptionFlags(),
|
|
|
|
format.format, vk::SampleCountFlagBits::e1,
|
2025-04-22 02:46:51 +02:00
|
|
|
vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eStore,
|
2025-04-21 21:40:30 +02:00
|
|
|
vk::AttachmentLoadOp::eDontCare, vk::AttachmentStoreOp::eDontCare,
|
|
|
|
vk::ImageLayout::eUndefined, vk::ImageLayout::ePresentSrcKHR);
|
|
|
|
vk::AttachmentReference attachment_ref = vk::AttachmentReference(0, vk::ImageLayout::eColorAttachmentOptimal);
|
|
|
|
vk::SubpassDescription subpass_description = {};
|
|
|
|
subpass_description.pipelineBindPoint = vk::PipelineBindPoint::eGraphics;
|
|
|
|
subpass_description.colorAttachmentCount = 1;
|
|
|
|
subpass_description.pColorAttachments = &attachment_ref;
|
|
|
|
|
2025-04-22 02:46:51 +02:00
|
|
|
vk::SubpassDependency subpass_dependency = {};
|
|
|
|
subpass_dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
|
|
|
subpass_dependency.dstSubpass = 0;
|
2025-04-24 04:13:58 +02:00
|
|
|
subpass_dependency.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
|
2025-04-22 02:46:51 +02:00
|
|
|
subpass_dependency.dstStageMask = vk::PipelineStageFlags(vk::PipelineStageFlagBits::eColorAttachmentOutput);
|
|
|
|
subpass_dependency.dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
|
|
|
|
|
2025-04-21 21:40:30 +02:00
|
|
|
vk::RenderPassCreateInfo render_pass_info = {};
|
|
|
|
render_pass_info.attachmentCount = 1;
|
|
|
|
render_pass_info.pAttachments = &color_attachment;
|
|
|
|
render_pass_info.subpassCount = 1;
|
|
|
|
render_pass_info.pSubpasses = &subpass_description;
|
2025-04-22 02:46:51 +02:00
|
|
|
render_pass_info.dependencyCount = 1;
|
|
|
|
render_pass_info.pDependencies = &subpass_dependency;
|
2025-04-21 21:40:30 +02:00
|
|
|
|
|
|
|
vk::RenderPass render_pass = device.createRenderPass(render_pass_info);
|
|
|
|
|
|
|
|
vk::GraphicsPipelineCreateInfo pipeline_info = {};
|
|
|
|
pipeline_info.stageCount = 2;
|
|
|
|
pipeline_info.pStages = pipeline_shaders.data();
|
|
|
|
pipeline_info.pVertexInputState = &vertex_input_info;
|
|
|
|
pipeline_info.pInputAssemblyState = &input_assembly_info;
|
|
|
|
pipeline_info.pViewportState = &viewport_info;
|
|
|
|
pipeline_info.pRasterizationState = &raster_info;
|
|
|
|
pipeline_info.pMultisampleState = &multisampling_info;
|
|
|
|
pipeline_info.pColorBlendState = &color_blend_info;
|
|
|
|
pipeline_info.layout = pipeline_layout;
|
|
|
|
pipeline_info.renderPass = render_pass;
|
|
|
|
pipeline_info.subpass = 0;
|
|
|
|
pipeline_info.basePipelineHandle = VK_NULL_HANDLE;
|
|
|
|
pipeline_info.basePipelineIndex = -1;
|
|
|
|
|
|
|
|
auto pipeline_result = device.createGraphicsPipeline(VK_NULL_HANDLE, pipeline_info);
|
|
|
|
|
|
|
|
if (pipeline_result.result != vk::Result::eSuccess)
|
2025-04-18 06:18:45 +02:00
|
|
|
{
|
2025-04-21 21:40:30 +02:00
|
|
|
std::println("Pipeline creation failed!");
|
|
|
|
return -1;
|
2025-04-18 06:18:45 +02:00
|
|
|
}
|
2025-04-21 21:40:30 +02:00
|
|
|
vk::Pipeline pipeline = pipeline_result.value;
|
|
|
|
std::println("Pipeline creation success!");
|
|
|
|
|
2025-04-22 02:46:51 +02:00
|
|
|
|
|
|
|
std::vector<vk::Framebuffer> framebuffers;
|
|
|
|
|
|
|
|
for (auto &view: image_views)
|
|
|
|
{
|
|
|
|
vk::FramebufferCreateInfo framebuffer_info = vk::FramebufferCreateInfo(vk::FramebufferCreateFlags(),
|
|
|
|
render_pass, view, framebuffer_extension.width,
|
|
|
|
framebuffer_extension.height, 1);
|
|
|
|
framebuffers.push_back(device.createFramebuffer(framebuffer_info));
|
|
|
|
}
|
|
|
|
|
2025-04-24 04:13:58 +02:00
|
|
|
std::vector<vertex> vertices = {
|
2025-04-28 20:52:26 +02:00
|
|
|
{{-0.1f, -0.1f}, {1.0f, 0.0f, 0.0f}},
|
|
|
|
{{0.1f, -0.1f}, {1.0f, 0.0f, 0.0f}},
|
|
|
|
{{0.1f, 0.1f}, {0.0f, 1.0f, 0.0f}},
|
|
|
|
{{-0.1f, 0.1f}, {0.0f, 0.0f, 1.0f}}
|
2025-04-24 04:13:58 +02:00
|
|
|
};
|
2025-05-24 22:26:40 +02:00
|
|
|
vertices = convert_quad_to_triangles(vertices);
|
|
|
|
glm::mat2 transform = scale({1.0, 1.0}) * rotate(0.0f);
|
|
|
|
glm::vec2 movement = {0.0f, 0.0f};
|
2025-04-24 04:13:58 +02:00
|
|
|
|
2025-05-24 22:26:40 +02:00
|
|
|
for (auto &[position, color] : vertices)
|
|
|
|
{
|
|
|
|
position = position + movement;
|
|
|
|
position = transform * position;
|
|
|
|
}
|
2025-04-24 04:13:58 +02:00
|
|
|
|
|
|
|
vk::BufferCreateInfo buffer_info = vk::BufferCreateInfo(vk::BufferCreateFlags(), sizeof(vertices[0]) * vertices.size(), vk::BufferUsageFlagBits::eVertexBuffer, vk::SharingMode::eExclusive);
|
|
|
|
vk::Buffer vertex_buffer = device.createBuffer(buffer_info);
|
|
|
|
VkMemoryRequirements memory_requirements;
|
|
|
|
vkGetBufferMemoryRequirements(device, vertex_buffer, &memory_requirements);
|
|
|
|
vk::PhysicalDeviceMemoryProperties memory_propierties = selected_physical_device.getMemoryProperties();
|
|
|
|
|
|
|
|
int propierty_index = -1;
|
|
|
|
for (int i = 0; i < memory_propierties.memoryTypeCount; i++)
|
|
|
|
{
|
|
|
|
if (memory_propierties.memoryTypes[i].propertyFlags & vk::MemoryPropertyFlags(vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent))
|
|
|
|
{
|
|
|
|
propierty_index = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (propierty_index == -1)
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Didnt find a suitable memory");
|
|
|
|
}
|
|
|
|
|
|
|
|
vk::MemoryAllocateInfo alloc_info = vk::MemoryAllocateInfo(memory_requirements.size, propierty_index);
|
|
|
|
|
|
|
|
vk::DeviceMemory vertex_buffer_memory = device.allocateMemory(alloc_info);
|
|
|
|
device.bindBufferMemory(vertex_buffer, vertex_buffer_memory, 0);
|
|
|
|
|
|
|
|
char *data = (char *)device.mapMemory(vertex_buffer_memory, 0, buffer_info.size);
|
2025-04-28 20:52:26 +02:00
|
|
|
memcpy(data, vertices.data(), buffer_info.size);
|
2025-04-26 05:52:05 +02:00
|
|
|
|
2025-04-22 02:46:51 +02:00
|
|
|
|
|
|
|
vk::CommandPoolCreateInfo command_pool_info = {};
|
|
|
|
command_pool_info.flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer;
|
|
|
|
command_pool_info.queueFamilyIndex = graphics_queue_index;
|
|
|
|
vk::CommandPool command_pool = device.createCommandPool(command_pool_info);
|
|
|
|
|
|
|
|
vk::CommandBufferAllocateInfo cmd_alloc_info = vk::CommandBufferAllocateInfo(command_pool,
|
|
|
|
vk::CommandBufferLevel::ePrimary,
|
|
|
|
1);
|
|
|
|
auto command_buffers = device.allocateCommandBuffers(cmd_alloc_info);
|
|
|
|
|
|
|
|
vk::SemaphoreCreateInfo semaphore_info = vk::SemaphoreCreateInfo();
|
|
|
|
vk::FenceCreateInfo fence_info = vk::FenceCreateInfo();
|
|
|
|
fence_info.flags = vk::FenceCreateFlagBits::eSignaled;
|
|
|
|
vk::Semaphore image_semaphore = device.createSemaphore(semaphore_info);
|
|
|
|
vk::Semaphore render_semaphore = device.createSemaphore(semaphore_info);
|
|
|
|
vk::Fence next_frame_fence = device.createFence(fence_info);
|
2025-05-26 22:40:20 +02:00
|
|
|
player.x = 0.0f;
|
|
|
|
player.y = 0.0f;
|
|
|
|
player.height = 0.2f;
|
|
|
|
player.width = 0.2f;
|
|
|
|
//velocityX = 0.008f;
|
2025-05-24 22:26:40 +02:00
|
|
|
std::vector<vertex> render_vertices = vertices;
|
2025-05-25 01:32:59 +02:00
|
|
|
float angle = 0.0f;
|
|
|
|
float vel2 = 0.005f;
|
2025-05-26 22:40:20 +02:00
|
|
|
//std::thread phy_thread(simple_physics);
|
|
|
|
auto before = clock::now();
|
2025-04-18 06:18:45 +02:00
|
|
|
while(!glfwWindowShouldClose(window))
|
|
|
|
{
|
|
|
|
glfwPollEvents();
|
2025-04-28 20:52:26 +02:00
|
|
|
auto res_wait = device.waitForFences(next_frame_fence, VK_TRUE, UINT64_MAX);
|
|
|
|
if (res_wait != vk::Result::eSuccess)
|
|
|
|
throw std::runtime_error("failed waiting!");
|
2025-04-22 02:46:51 +02:00
|
|
|
device.resetFences(next_frame_fence);
|
2025-04-28 20:52:26 +02:00
|
|
|
if (skip_rendering)
|
|
|
|
continue;
|
|
|
|
auto image_result = device.acquireNextImageKHR(swapchain, UINT64_MAX, image_semaphore);
|
|
|
|
if (image_result.result != vk::Result::eSuccess)
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Getting next image failed!");
|
|
|
|
}
|
|
|
|
uint32_t image_index = image_result.value;
|
2025-04-22 02:46:51 +02:00
|
|
|
vkResetCommandBuffer(command_buffers[0], 0);
|
2025-05-26 22:40:20 +02:00
|
|
|
auto time_elapsed = clock::now() - before;
|
|
|
|
simple_physics_step(std::chrono::duration_cast<std::chrono::duration<float>>(time_elapsed).count());
|
|
|
|
before = clock::now();
|
2025-05-24 22:26:40 +02:00
|
|
|
for (int i = 0; i < vertices.size(); i++)
|
|
|
|
{
|
2025-05-25 01:32:59 +02:00
|
|
|
render_vertices[i].position = vertices[i].position * rotate(angle);
|
2025-05-26 22:40:20 +02:00
|
|
|
render_vertices[i].position = glm::vec2(move({player.x, player.y}) * glm::vec3(render_vertices[i].position, 1.0f));
|
2025-04-22 02:46:51 +02:00
|
|
|
}
|
2025-05-25 01:32:59 +02:00
|
|
|
angle -= 1.0f;
|
2025-05-24 22:26:40 +02:00
|
|
|
memcpy(data, render_vertices.data(), buffer_info.size);
|
2025-04-28 20:52:26 +02:00
|
|
|
|
|
|
|
|
|
|
|
vk::CommandBufferBeginInfo begin_info = {};
|
2025-04-22 02:46:51 +02:00
|
|
|
vk::ClearValue clear_color = vk::ClearValue({0.0f, 0.0f, 0.0f, 1.0f});
|
|
|
|
vk::Rect2D render_area = {{0, 0}, framebuffer_extension};
|
|
|
|
vk::RenderPassBeginInfo render_pass_begin = vk::RenderPassBeginInfo(render_pass, framebuffers[image_index],
|
|
|
|
render_area, 1, &clear_color);
|
2025-04-24 04:13:58 +02:00
|
|
|
vk::DeviceSize offset = 0;
|
2025-04-28 20:52:26 +02:00
|
|
|
command_buffers[0].begin(begin_info);
|
2025-04-22 02:46:51 +02:00
|
|
|
command_buffers[0].beginRenderPass(render_pass_begin, vk::SubpassContents::eInline);
|
|
|
|
command_buffers[0].bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
|
2025-04-24 04:13:58 +02:00
|
|
|
//command_buffers[0].setViewport(0, viewport);
|
|
|
|
//command_buffers[0].setScissor(0, scissor);
|
|
|
|
|
|
|
|
command_buffers[0].bindVertexBuffers(0, 1, &vertex_buffer, &offset);
|
2025-04-28 20:52:26 +02:00
|
|
|
command_buffers[0].draw(vertices.size(), 1, 0, 0);
|
2025-04-22 02:46:51 +02:00
|
|
|
command_buffers[0].endRenderPass();
|
|
|
|
if (vkEndCommandBuffer(command_buffers[0]) != VK_SUCCESS)
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Command buffer creation failed!");
|
|
|
|
}
|
|
|
|
|
|
|
|
vk::PipelineStageFlags flags = vk::PipelineStageFlags(vk::PipelineStageFlagBits::eColorAttachmentOutput);
|
|
|
|
vk::SubmitInfo submit_info = vk::SubmitInfo();
|
|
|
|
submit_info.waitSemaphoreCount = 1;
|
|
|
|
submit_info.pWaitSemaphores = &image_semaphore;
|
|
|
|
submit_info.pWaitDstStageMask = &flags;
|
|
|
|
submit_info.signalSemaphoreCount = 1;
|
|
|
|
submit_info.pSignalSemaphores = &render_semaphore;
|
|
|
|
submit_info.commandBufferCount = 1;
|
|
|
|
submit_info.pCommandBuffers = &command_buffers[0];
|
|
|
|
|
|
|
|
graphics_queue.submit(submit_info, next_frame_fence);
|
|
|
|
|
|
|
|
vk::PresentInfoKHR present_info = {};
|
|
|
|
present_info.waitSemaphoreCount = 1;
|
|
|
|
present_info.pWaitSemaphores = &render_semaphore;
|
|
|
|
present_info.swapchainCount = 1;
|
|
|
|
present_info.pSwapchains = &swapchain;
|
|
|
|
present_info.pImageIndices = &image_index;
|
|
|
|
|
2025-04-28 20:52:26 +02:00
|
|
|
auto present_result = graphics_queue.presentKHR(present_info);
|
|
|
|
if (present_result != vk::Result::eSuccess)
|
|
|
|
throw std::runtime_error("Presenting to the graphics queue failed");
|
2025-04-22 02:46:51 +02:00
|
|
|
}
|
2025-05-26 22:40:20 +02:00
|
|
|
thread = false;
|
|
|
|
//phy_thread.join();
|
2025-04-26 05:52:05 +02:00
|
|
|
device.unmapMemory(vertex_buffer_memory);
|
2025-04-24 04:13:58 +02:00
|
|
|
device.waitIdle();
|
|
|
|
device.destroyBuffer(vertex_buffer);
|
|
|
|
device.freeMemory(vertex_buffer_memory);
|
2025-04-22 02:46:51 +02:00
|
|
|
for (auto &framebuffer: framebuffers)
|
|
|
|
{
|
|
|
|
device.destroyFramebuffer(framebuffer);
|
2025-04-18 06:18:45 +02:00
|
|
|
}
|
2025-04-22 02:46:51 +02:00
|
|
|
device.destroyFence(next_frame_fence);
|
|
|
|
device.destroySemaphore(render_semaphore);
|
|
|
|
device.destroySemaphore(image_semaphore);
|
|
|
|
device.destroyCommandPool(command_pool);
|
2025-04-21 21:40:30 +02:00
|
|
|
device.destroyPipeline(pipeline);
|
|
|
|
device.destroyRenderPass(render_pass);
|
|
|
|
device.destroyPipelineLayout(pipeline_layout);
|
|
|
|
device.destroyShaderModule(vertex_module);
|
|
|
|
device.destroyShaderModule(fragment_module);
|
|
|
|
for (auto &image: image_views)
|
|
|
|
{
|
|
|
|
device.destroyImageView(image);
|
|
|
|
}
|
2025-04-18 06:18:45 +02:00
|
|
|
device.destroySwapchainKHR(swapchain);
|
|
|
|
instance.destroySurfaceKHR(surface);
|
|
|
|
device.destroy();
|
|
|
|
instance.destroy();
|
|
|
|
glfwTerminate();
|
|
|
|
return 0;
|
|
|
|
}
|