#include "WorldRenderer.hpp" #include #include #include #include #include "imgui.h" #include "shaders/ShaderInputSet.h" #include "shaders/ShaderInputSetLayoutBuilder.hpp" #include "SDLWindow.h" #include "Swapchain.hpp" #include "RenderGraphBuilder.hpp" #include "draw/RenderPasses/CharacterRenderPass.hpp" #include "ImGuiRenderPass.hpp" #include "draw/RenderPasses/TerrainRenderPass.hpp" #include "world/Camera.hpp" #include "world/World.hpp" namespace tw::drw { void lft_dbg_callback(lft::dbg::LogMessageSeverity severity, lft::dbg::LogMessageType type, const char *__restrict format, va_list args) { const char* titles[3] = { "\033[0;34m[info]:", "\033[0;33m[warn]:", "\033[0;31m[fail]:" }; fwrite(titles[severity], 14, 1, stdout); if(args != nullptr) { vfprintf(stdout, format, args); } else { fwrite(format, 1, strlen(format), stdout); } fwrite("\033[0m", 4, 1, stdout); printf("\n"); } Instance create_instance(const std::string& name, const lft::win::Window* window) { std::vector required_extensions = window->get_required_extensions(); // required_extensions.push_back(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME); std::vector required_layers = { #if DEBUG "VK_LAYER_KHRONOS_validation" #endif }; /** * Instance initializes a connection with Vulkan driver */ return Instance( name, name, required_extensions, required_layers, lft_dbg_callback); } Surface create_surface(lft::win::SDLWindow* window, const Instance* instance) { return window->create_surface(instance); } lft::rg::RenderGraph WorldRenderer::init_render_graph() { auto m_imgui_rp = new gui::ImGuiRenderPass(&m_gpu, (const lft::win::SDLWindow*)m_window); auto m_character_rp = new CharacterRenderPass(this, &m_shader_manager); auto m_terrain_rp = new TerrainRenderPass(this, &m_shader_manager); m_rendergraph_builder.add_task(m_imgui_rp->get_render_task().build()); m_rendergraph_builder.add_task(m_character_rp->get_render_task().build()); m_rendergraph_builder.add_task(m_terrain_rp->get_render_task().build()); return m_rendergraph_builder.build(); } VkDescriptorSetLayout create_global_descriptor_set_layout(const Gpu* gpu) { return ShaderInputSetLayoutBuilder() .uniform_buffer(0) .build(gpu); } VkDescriptorSet create_global_descriptor_set( const Gpu* gpu, VkDescriptorSetLayout descriptor_set_layout, Buffer camera_buffer ) { return ShaderInputSetBuilder() .buffer(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, camera_buffer, 0, sizeof(glm::mat4) * 2 + sizeof(glm::vec4)) .build(gpu, descriptor_set_layout); } Buffer create_camera_buffer(const Gpu *gpu) { MemoryAllocationInfo allocInfo = { .usage = MEMORY_USAGE_AUTO_PREFER_DEVICE, .requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, }; BufferCreateInfo bufferInfo = { .size = sizeof(CameraData), .usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, .isExclusive = true }; Buffer buffer; gpu->memory()->create_buffer(&bufferInfo, &allocInfo, &buffer); return buffer; } WorldRenderer::WorldRenderer( const std::string& name, const lft::win::Window* window, const World* world, const io::Files* files ) : m_window(window), m_surface(create_surface((lft::win::SDLWindow*)(m_window), &m_instance)), m_instance(create_instance(name, m_window)), m_gpu(&m_instance, &m_surface), m_swapchain(&m_gpu, m_window->get_size(), &m_surface), m_files(files), m_shader_manager(&m_gpu, m_files), m_wait_on_image_fence(m_gpu.create_fence(false)), m_camera_buffer(create_camera_buffer(&m_gpu)), m_global_descriptor_set_layout(create_global_descriptor_set_layout(&m_gpu)), m_global_descriptor_set(create_global_descriptor_set(&m_gpu, m_global_descriptor_set_layout, m_camera_buffer)), m_world(world), m_mesh_buffer(&m_gpu), m_rendergraph_builder(&m_gpu, ImageChain::from_swapchain(m_swapchain), "swapchain"), m_rendergraph(init_render_graph()), m_camera(720.0f / 480.0f) { } void WorldRenderer::update_camera_buffer() { void *pData = nullptr; m_gpu.memory()->map(m_camera_buffer.allocation, &pData); memcpy(pData, m_camera.data(), sizeof(CameraData)); m_gpu.memory()->unmap(m_camera_buffer.allocation); } void WorldRenderer::render() { if(!m_window->has_size(m_last_window_size)) { vkDeviceWaitIdle(m_gpu.dev()); m_swapchain.resize(m_window->get_size()); m_rendergraph_builder.set_image_chain(ImageChain::from_swapchain(m_swapchain)); m_rendergraph = m_rendergraph_builder.build(); m_last_window_size = m_window->get_size(); } uint32_t imageIdx = 0; auto result = m_swapchain.get_next_image_idx( VK_NULL_HANDLE, m_wait_on_image_fence, &imageIdx); if(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { std::println("Rebuilding"); m_rendergraph_builder.build(); } update_camera_buffer(); m_rendergraph.run(imageIdx, VK_NULL_HANDLE, m_wait_on_image_fence); m_swapchain.present({ m_rendergraph.buffer(0).final_signal(imageIdx) }, imageIdx); } }