From db41d43345ea73cf7c1bbb29448e52ffb822e3e0 Mon Sep 17 00:00:00 2001 From: vimene Date: Tue, 13 Jan 2026 02:04:52 +0100 Subject: added textures for the hardware renderer - removed "using" directive in .hpp - reverse order of arguments for quaternion rotation, i.e. q.rot(v) instead of v.rot(q), where q is a quaterinon and v a vector - pass the inverse of the view matrix to render_and_present_frame, to allow light calculation in shaders (we used to just pass the matrix of the quaternion of the transformation, i.e. discard scaling and translations) - added another mesh and texture (viking_room) for testing purposes - added transparent background option - added Quaternion::look_towards(), which is the equivalent of Matrix4::look_at() but only for rotations - various improvement to .obj parsing - load texture coordinates from .obj file - merged duplicate vertices in Mesh::linearize_indices() --- src/engine.cpp | 249 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 147 insertions(+), 102 deletions(-) (limited to 'src/engine.cpp') diff --git a/src/engine.cpp b/src/engine.cpp index bde3058..aed0970 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -55,6 +55,7 @@ using engine::fb::CharacterFrameBuffer, engine::fb::PixelFrameBuffer, engine::o3d::Scene, + engine::o3d::Object3D, engine::o3d::Mesh, engine::o3d::Triangle, engine::o3d::Camera, @@ -82,9 +83,10 @@ enum class GameType { plane, suzanne, plane_and_suzanne, + test, }; -constexpr GameType game_type { GameType::plane_and_suzanne }; +constexpr GameType game_type { GameType::test }; static void print_usage(std::ostream& output_stream) { output_stream << "Usage: ./engine [-htg] [--help] [--term] [--graphical]\n" @@ -139,7 +141,7 @@ static void scene_main(const Matrix4& final_transform_mat, Scene& scene, if (kb.is_down(KeyboardKey::fw) || kb.is_down(KeyboardKey::key_left) || kb.is_down(KeyboardKey::bw) || kb.is_down(KeyboardKey::key_right)) movement.normalize(); - scene.camera.transform.loc += movement.rot(Quaternion::rot_y(ry)) * movement_speed * ellapsed_time; + scene.camera.transform.loc += Quaternion::rot_y(ry).rot(movement) * movement_speed * ellapsed_time; scene.camera.transform.rot = Quaternion::euler_zxy(rx, ry, 0.f); scene.camera.fov = (kb.is_down(KeyboardKey::zoom) ? 40.f : 80.f) * PI / 180.f; @@ -152,7 +154,7 @@ static void scene_main(const Matrix4& final_transform_mat, Scene& scene, auto proj_mat = final_transform_mat * Matrix4::perspective(scene.camera.fov, static_cast(surface_width) / static_cast(surface_height), .5f, 12.f); - render_and_present_frame(scene.camera.transform.to_inverse_mat4(), proj_mat, time, ellapsed_time); + render_and_present_frame(scene.camera.transform.to_inverse_mat4(), proj_mat, scene.camera.transform.to_mat4(), time, ellapsed_time); } } @@ -162,7 +164,7 @@ static void render_software(Renderer& renderer, const Matrix4& fina PollEventsFn poll_events, UpdateRendererSizeFn update_renderer_size, PresentFrameFn present_frame) { scene_main(final_transform_mat, scene, // update_surface_size - [&]() { + [&] { update_renderer_size(); return std::tuple { renderer.width(), renderer.height() }; }, @@ -170,25 +172,33 @@ static void render_software(Renderer& renderer, const Matrix4& fina poll_events, // render_and_present_frame - [&](const Matrix4& view_mat, const Matrix4& proj_mat, float /* time */, float /* ellapsed_time */) { - auto proj_view_mat = proj_mat * view_mat; + [&](const Matrix4& /* view_mat */, const Matrix4& /* proj_mat */, const Matrix4& /* inv_view_mat */, float /* time */, float /* ellapsed_time */) { + // TODO: remove renderer.clear(); - for (const auto& obj : scene.objs) { - auto model_mat = obj.transform.to_mat4(); - auto final_mat = proj_view_mat * model_mat; - const auto& mesh = obj.mesh; - std::vector vertices; - std::vector vertices_data; - for (const auto& vertex : mesh.vertices) { - vertices.push_back(final_mat * Vector4 { vertex, 1.f }); - vertices_data.push_back(VertexData((model_mat * vertex).xyz())); - } - for (const auto& triangle_indices : mesh.indices) { - [&](std::integer_sequence) { - renderer.draw_triangle({{vertices[triangle_indices[j][0]], mesh.normals[triangle_indices[j][1]], vertices_data[triangle_indices[j][0]]}...}); - }(std::make_integer_sequence()); - } - } + // auto proj_view_mat = proj_mat * view_mat; + // renderer.clear(); + // for (const auto& obj : scene.objs) { + // auto model_mat = obj.transform.to_mat4(); + // auto final_mat = proj_view_mat * model_mat; + // const auto& mesh = obj.mesh; + // std::vector vertices; + // std::vector normals; + // std::vector vertices_data; + // for (const auto& vertex : mesh.vertices) { + // Vector4 vertex4 { vertex, 1.f }; + // vertices.push_back(final_mat * vertex4); + // vertices_data.push_back(VertexData((model_mat * vertex4).xyz())); + // } + // for (const auto& normal : mesh.normals) + // normals.push_back((model_mat * Vector4 { normal, 0.f }).xyz()); + // for (const auto& triangle_indices : mesh.indices) { + // [&](std::index_sequence) { + // renderer.draw_triangle( + // {{vertices[triangle_indices[j][0]], normals[triangle_indices[j][1]], vertices_data[triangle_indices[j][0]]}...} + // ); + // }(std::make_index_sequence<3>()); + // } + // } present_frame(); } ); @@ -208,10 +218,10 @@ static int main_term(Scene& scene) { set_escdelay(0); curs_set(0); - auto renderer = [&]() { + auto renderer = [&] { int w, h; getmaxyx(stdscr, h, w); - return Renderer { CharacterFrameBuffer { static_cast(w), static_cast(h) } }; + return Renderer { CharacterFrameBuffer { static_cast(w), static_cast(h) } }; }(); render_software(renderer, Matrix4::scale(Vector3(2.f, 1.f, 1.f)), scene, @@ -289,14 +299,14 @@ static int main_term(Scene& scene) { }, // update_renderer_size - [&]() { + [&] { int w, h; getmaxyx(stdscr, h, w); renderer.resize(static_cast(w), static_cast(h)); }, // present_frame - [&]() { + [&] { mvaddnstr(0, 0, renderer.fb.chars(), renderer.width() * renderer.height()); } ); @@ -331,6 +341,7 @@ constexpr bool enable_validation_layers = true; constexpr size_t max_frames_in_flight = 2; constexpr bool show_fps = false; +constexpr bool transparent_window = false; struct PhysicalDeviceEntry { uint32_t idx; @@ -347,7 +358,7 @@ enum class GraphicalRendererMode { }; static bool check_validation_layer_support() { - auto avail_layers = [&]() { + auto avail_layers = [&] { uint32_t avail_layers_count; if (VkResult res = vkEnumerateInstanceLayerProperties(&avail_layers_count, nullptr); res != VK_SUCCESS) { std::cerr << "failed to enumerate instance layer properties, error code: " << string_VkResult(res) << std::endl; @@ -477,7 +488,7 @@ static uint32_t find_mem_type(VkPhysicalDevice physical_device, uint32_t type_fi static std::tuple create_buf(VkPhysicalDevice physical_device, VkDevice device, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags mem_flags) { - auto buf = [&]() { + auto buf = [&] { VkBufferCreateInfo buf_ci { .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, @@ -499,7 +510,7 @@ create_buf(VkPhysicalDevice physical_device, VkDevice device, VkDeviceSize size, VkMemoryRequirements buf_mem_requirements; vkGetBufferMemoryRequirements(device, buf, &buf_mem_requirements); - auto buf_device_mem = [&]() { + auto buf_device_mem = [&] { VkMemoryAllocateInfo buf_mem_ai { .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, .pNext = nullptr, @@ -522,7 +533,7 @@ create_buf(VkPhysicalDevice physical_device, VkDevice device, VkDeviceSize size, } static VkCommandBuffer begin_single_time_cmds(VkDevice device, VkCommandPool cmd_pool) { - auto cmd_buf = [&]() { + auto cmd_buf = [&] { VkCommandBufferAllocateInfo cmd_buf_ai { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, .pNext = nullptr, @@ -612,7 +623,7 @@ static void copy_buf_to_img(VkCommandBuffer cmd_buf, VkBuffer src, VkImage dst, static std::tuple create_img(VkPhysicalDevice physical_device, VkDevice device, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags mem_flags) { - auto texture_img = [&]() { + auto texture_img = [&] { VkImageCreateInfo img_ci { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .pNext = nullptr, @@ -639,7 +650,7 @@ create_img(VkPhysicalDevice physical_device, VkDevice device, uint32_t width, ui return texture_img; }(); - auto texture_img_device_mem = [&]() { + auto texture_img_device_mem = [&] { VkMemoryRequirements mem_requirements; vkGetImageMemoryRequirements(device, texture_img, &mem_requirements); VkMemoryAllocateInfo mem_ai { @@ -668,7 +679,7 @@ static std::tuple create_depth_resources(VkPhysicalDevice physical_device, VkDevice device, VkExtent2D swapchain_extent, VkFormat depth_format) { auto [depth_img, depth_img_device_mem] = create_img(physical_device, device, swapchain_extent.width, swapchain_extent.height, depth_format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - auto depth_img_view = [&]() { + auto depth_img_view = [&] { VkImageViewCreateInfo img_view_ci { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .pNext = {}, @@ -743,6 +754,10 @@ static int main_graphical(Scene& scene) { // init window glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + if (transparent_window) { + glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); + glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); + } bool fb_resized = false; @@ -777,7 +792,7 @@ static int main_graphical(Scene& scene) { exit(EXIT_FAILURE); } - auto instance = [&]() { + auto instance = [&] { VkApplicationInfo app_info { .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .pNext = nullptr, @@ -788,7 +803,7 @@ static int main_graphical(Scene& scene) { .apiVersion = VK_API_VERSION_1_4, }; - auto instance_exts = [&]() { + auto instance_exts = [&] { std::vector instance_exts; { uint32_t glfw_extension_count; @@ -800,7 +815,7 @@ static int main_graphical(Scene& scene) { return instance_exts; }(); - auto avail_instance_exts = [&]() { + auto avail_instance_exts = [&] { uint32_t avail_instance_exts_count; if (VkResult res = vkEnumerateInstanceExtensionProperties(nullptr, &avail_instance_exts_count, nullptr); res != VK_SUCCESS) { std::cerr << "failed to enumerate instance extension properties, error code: " << string_VkResult(res) << std::endl; @@ -863,7 +878,7 @@ static int main_graphical(Scene& scene) { } // create window surface - auto surface = [&]() { + auto surface = [&] { VkSurfaceKHR surface; if (VkResult res = glfwCreateWindowSurface(instance, window, nullptr, &surface); res != VK_SUCCESS) { std::cerr << "failed to create window surface, error code: " << string_VkResult(res) << std::endl; @@ -873,10 +888,10 @@ static int main_graphical(Scene& scene) { }(); // select physical device and queues - auto [physical_device, graphics_queue_family_index, present_queue_family_index, physical_device_props, physical_device_features, depth_format] = [&]() { + auto [physical_device, graphics_queue_family_index, present_queue_family_index, physical_device_props, physical_device_features, depth_format] = [&] { std::multimap physical_devices; - auto avail_physical_devices = [&]() { + auto avail_physical_devices = [&] { uint32_t avail_physical_devices_count; if (VkResult res = vkEnumeratePhysicalDevices(instance, &avail_physical_devices_count, nullptr); res != VK_SUCCESS) { std::cerr << "failed to enumerate physical devices, error code: " << string_VkResult(res) << std::endl; @@ -900,7 +915,7 @@ static int main_graphical(Scene& scene) { for (uint32_t i = 0; i < avail_physical_devices.size(); i++) { const auto& avail_physical_device = avail_physical_devices[i]; - auto physical_device_props = [&]() { + auto physical_device_props = [&] { VkPhysicalDeviceProperties2 physical_device_props{}; physical_device_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; vkGetPhysicalDeviceProperties2(avail_physical_device, &physical_device_props); @@ -910,14 +925,14 @@ static int main_graphical(Scene& scene) { std::cout << " " << (i + 1) << ". " << physical_device_props.properties.deviceName << ":" << std::endl; std::cout << " apiVersion: " << engine::vk::api { physical_device_props.properties.apiVersion } << std::endl; - auto physical_device_features = [&]() { + auto physical_device_features = [&] { VkPhysicalDeviceFeatures2 physical_device_features{}; physical_device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; vkGetPhysicalDeviceFeatures2(avail_physical_device, &physical_device_features); return physical_device_features; }(); - auto physical_device_ext_props = [&]() { + auto physical_device_ext_props = [&] { uint32_t physical_device_ext_props_count; if (VkResult res = vkEnumerateDeviceExtensionProperties(avail_physical_device, nullptr, &physical_device_ext_props_count, nullptr); res != VK_SUCCESS) { @@ -941,7 +956,7 @@ static int main_graphical(Scene& scene) { std::cout << " " << ext << std::endl; } - auto queue_family_properties = [&]() { + auto queue_family_properties = [&] { uint32_t queue_family_properties_count; vkGetPhysicalDeviceQueueFamilyProperties2(avail_physical_device, &queue_family_properties_count, nullptr); std::vector queue_family_properties(queue_family_properties_count); @@ -975,7 +990,7 @@ static int main_graphical(Scene& scene) { std::cout << "none"; std::cout << std::endl; - auto score = [&]() { + auto score = [&] { if (VK_API_VERSION_VARIANT(physical_device_props.properties.apiVersion) != 0 || physical_device_props.properties.apiVersion < VK_API_VERSION_1_4) return std::optional {}; @@ -1051,7 +1066,7 @@ static int main_graphical(Scene& scene) { best->second.present_queue_family_index, best->second.props, best->second.features, best->second.depth_format }; }(); - auto device = [&]() { + auto device = [&] { // TODO: really weird way of making a single structure if // graphics_queue_family_index == present_queue_family_index // here, in this cas, we create both *CreateInfo, and then tell VkDeviceCreateInfo that @@ -1135,7 +1150,7 @@ static int main_graphical(Scene& scene) { return device; }(); - auto [graphics_queue, present_queue] = [&]() { + auto [graphics_queue, present_queue] = [&] { const auto map_family_to_queue = [&](uint32_t queue_family_index) { VkQueue queue; vkGetDeviceQueue(device, queue_family_index, 0, &queue); @@ -1166,13 +1181,13 @@ static int main_graphical(Scene& scene) { VkDeviceMemory depth_img_device_mem; VkImageView depth_img_view; - const auto destroy_swapchain = [&]() { + const auto destroy_swapchain = [&] { for (auto it_img_view = swapchain_img_views.rbegin(); it_img_view != swapchain_img_views.rend(); ++it_img_view) vkDestroyImageView(device, *it_img_view, nullptr); vkDestroySwapchainKHR(device, swapchain, nullptr); }; - const auto recreate_swapchain = [&]() { + const auto recreate_swapchain = [&] { bool is_first_swapchain = (swapchain == nullptr); if (!is_first_swapchain) { if (VkResult res = vkDeviceWaitIdle(device); res != VK_SUCCESS) { @@ -1185,7 +1200,7 @@ static int main_graphical(Scene& scene) { // TODO: should probably use version 2 of theses functions, but glfwCreateWindowSurface // return version 1, so for now we will use version 1 - auto surface_capabilities = [&]() { + auto surface_capabilities = [&] { VkSurfaceCapabilitiesKHR surface_capabilities; if (VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &surface_capabilities); res != VK_SUCCESS) { std::cerr << "failed to get physical device surface capabilities, error code: " << string_VkResult(res) << std::endl; @@ -1202,8 +1217,16 @@ static int main_graphical(Scene& scene) { exit(EXIT_FAILURE); } } + { + VkCompositeAlphaFlagsKHR required_composite_alpha = + (transparent_window ? VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR); + if ((surface_capabilities.supportedCompositeAlpha & required_composite_alpha) != required_composite_alpha) { + std::cerr << "required composite alpha flags not present" << std::endl; + exit(EXIT_FAILURE); + } + } - swapchain_extent = [&]() { + swapchain_extent = [&] { if (surface_capabilities.currentExtent.width != std::numeric_limits::max()) return surface_capabilities.currentExtent; int width, height; @@ -1220,8 +1243,8 @@ static int main_graphical(Scene& scene) { }; }(); - surface_format = [&]() { - auto surface_formats = [&]() { + surface_format = [&] { + auto surface_formats = [&] { uint32_t surface_formats_count; if (VkResult res = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &surface_formats_count, nullptr); res != VK_SUCCESS) { std::cerr << "failed to get physical device surface formats, error code: " << string_VkResult(res) << std::endl; @@ -1246,9 +1269,9 @@ static int main_graphical(Scene& scene) { exit(EXIT_FAILURE); }(); - [&]() { - auto present_mode = [&]() { - auto present_modes = [&]() { + [&] { + auto present_mode = [&] { + auto present_modes = [&] { uint32_t present_modes_count; if (VkResult res = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &present_modes_count, nullptr); res != VK_SUCCESS) { std::cerr << "failed to get physical device present modes, error code: " << string_VkResult(res) << std::endl; @@ -1293,7 +1316,7 @@ static int main_graphical(Scene& scene) { .queueFamilyIndexCount = {}, .pQueueFamilyIndices = {}, .preTransform = surface_capabilities.currentTransform, - .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .compositeAlpha = (transparent_window ? VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR), .presentMode = present_mode, .clipped = VK_TRUE, .oldSwapchain = {}, @@ -1316,7 +1339,7 @@ static int main_graphical(Scene& scene) { } }(); - [&]() { + [&] { uint32_t swapchain_imgs_count; if (VkResult res = vkGetSwapchainImagesKHR(device, swapchain, &swapchain_imgs_count, nullptr); res != VK_SUCCESS) { std::cerr << "failed to get swapchain images, error code: " << string_VkResult(res) << std::endl; @@ -1329,7 +1352,7 @@ static int main_graphical(Scene& scene) { } }(); - [&]() { + [&] { swapchain_img_views.resize(swapchain_imgs.size()); for (uint32_t i = 0; i < swapchain_imgs.size(); i++) { VkImageViewCreateInfo img_view_ci { @@ -1361,10 +1384,10 @@ static int main_graphical(Scene& scene) { recreate_swapchain(); - auto renderer_mode = GraphicalRendererMode::software; + auto renderer_mode = GraphicalRendererMode::hardware; // create descriptor set layout - auto descriptor_set_layout = [&]() { + auto descriptor_set_layout = [&] { std::array descriptor_set_layout_bindings { VkDescriptorSetLayoutBinding { .binding = 0, @@ -1397,10 +1420,10 @@ static int main_graphical(Scene& scene) { }(); // create pipeline - auto [pl_layout, graphics_pl] = [&]() { + auto [pl_layout, graphics_pl] = [&] { // reading shader file - auto shader_module = [&]() { - auto shader_code = [&]() { + auto shader_module = [&] { + auto shader_code = [&] { const char* shader_file_name = SHADERSDIR "/shader.spv"; std::ifstream shader_file(shader_file_name, std::ios::ate | std::ios::binary); if (!shader_file.is_open()) { @@ -1429,7 +1452,7 @@ static int main_graphical(Scene& scene) { return shader_module; }(); - auto [pl_layout, graphics_pl] = [&]() { + auto [pl_layout, graphics_pl] = [&] { std::array pl_shader_stage_cis { VkPipelineShaderStageCreateInfo { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, @@ -1563,7 +1586,7 @@ static int main_graphical(Scene& scene) { .blendConstants = { 0.f, 0.f, 0.f, 0.f }, }; - auto pl_layout = [&]() { + auto pl_layout = [&] { VkPipelineLayoutCreateInfo pl_layout_ci { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .pNext = nullptr, @@ -1628,7 +1651,7 @@ static int main_graphical(Scene& scene) { }(); // create command pool - auto cmd_pool = [&]() { + auto cmd_pool = [&] { VkCommandPoolCreateInfo cmd_pool_ci { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .pNext = nullptr, @@ -1649,9 +1672,9 @@ static int main_graphical(Scene& scene) { std::tie(depth_img, depth_img_device_mem, depth_img_view) = create_depth_resources(physical_device, device, swapchain_extent, depth_format); // create texture image - auto [texture_img, texture_img_device_mem] = [&]() { + auto [texture_img, texture_img_device_mem] = [&] { int w, h, channels; - stbi_uc* pixels = stbi_load(DATADIR "/assets/textures/texture.jpg", &w, &h, &channels, STBI_rgb_alpha); + stbi_uc* pixels = stbi_load(DATADIR "/assets/textures/viking_room.png", &w, &h, &channels, STBI_rgb_alpha); // TODO: we're also using this size as the host pixels buffer size, I don't know if mixing // the two will cause problems later. Right now they are the same, so it doesn't @@ -1708,7 +1731,7 @@ static int main_graphical(Scene& scene) { // TODO: this is the same code, with minor differences, than the one that create swapchain image // views, so maybe we should create a function. The thing is, this code only call a single // function with a single create-info, so I'm not sure if it would make sense - auto texture_img_view = [&]() { + auto texture_img_view = [&] { VkImageViewCreateInfo img_view_ci { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .pNext = {}, @@ -1734,7 +1757,7 @@ static int main_graphical(Scene& scene) { }(); // create texture sampler - auto sampler = [&]() { + auto sampler = [&] { VkSamplerCreateInfo sampler_ci { .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, .pNext = nullptr, @@ -1765,7 +1788,7 @@ static int main_graphical(Scene& scene) { }(); // create vertex buffers - auto [vertex_bufs, vertex_buf_device_mems] = [&]() { + auto [vertex_bufs, vertex_buf_device_mems] = [&] { std::vector vertex_bufs; std::vector vertex_buf_device_mems; for (const auto& vertices : meshes_vertices) { @@ -1817,7 +1840,7 @@ static int main_graphical(Scene& scene) { // TODO: this code is pretty much a duplicate with minor differences of the vertex_bufs one. We // should probably factor it out in a function. Also, every TODOs were remove for this one, but // they still hold - auto [index_bufs, index_buf_device_mems] = [&]() { + auto [index_bufs, index_buf_device_mems] = [&] { std::vector index_bufs; std::vector index_buf_device_mems; for (const auto& indices : meshes_indices) { @@ -1861,7 +1884,7 @@ static int main_graphical(Scene& scene) { }(); // create uniform buffers - auto [uniform_bufs, uniform_buf_device_mems, uniform_buf_mems] = [&]() { + auto [uniform_bufs, uniform_buf_device_mems, uniform_buf_mems] = [&] { constexpr VkDeviceSize uniform_buf_size = sizeof(engine::vk::UniformBufferObject); std::vector uniform_bufs(max_frames_in_flight * scene.objs.size(), nullptr); std::vector uniform_buf_device_mems(max_frames_in_flight * scene.objs.size(), nullptr); @@ -1879,7 +1902,7 @@ static int main_graphical(Scene& scene) { }(); // create descriptor pool - auto descriptor_pool = [&]() { + auto descriptor_pool = [&] { std::array descriptor_pool_sizes { VkDescriptorPoolSize { .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, @@ -1912,7 +1935,7 @@ static int main_graphical(Scene& scene) { // TODO: right now, we just send every descriptors every frame and for every object, without // taking into account update frequencies. For example we should have only one set for the // camera, shared between every objects, etc - auto descriptor_sets = [&]() { + auto descriptor_sets = [&] { std::vector layouts(max_frames_in_flight * scene.objs.size(), descriptor_set_layout); VkDescriptorSetAllocateInfo descriptor_set_ai { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, @@ -1974,7 +1997,7 @@ static int main_graphical(Scene& scene) { }(); // create command buffers - auto cmd_bufs = [&]() { + auto cmd_bufs = [&] { VkCommandBufferAllocateInfo cmd_buf_ai { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, .pNext = nullptr, @@ -1991,10 +2014,10 @@ static int main_graphical(Scene& scene) { }(); // create sync objects - auto [sems_present_complete, sems_render_finished] = [&]() { + auto [sems_present_complete, sems_render_finished] = [&] { // TODO: remove duplicate code - auto sems_present_complete = [&]() { + auto sems_present_complete = [&] { std::array sems_present_complete; size_t num = 0; for (auto& sem : sems_present_complete) { @@ -2011,7 +2034,7 @@ static int main_graphical(Scene& scene) { return sems_present_complete; }(); - auto sems_render_finished = [&]() { + auto sems_render_finished = [&] { std::vector sems_render_finished(swapchain_imgs.size()); size_t num = 0; for (auto& sem : sems_render_finished) { @@ -2050,7 +2073,7 @@ static int main_graphical(Scene& scene) { } std::cout << " ]" << std::endl; - auto fences_in_flight = [&]() { + auto fences_in_flight = [&] { std::array fences_in_flight; size_t num = 0; for (auto& fence_in_flight : fences_in_flight) { @@ -2087,7 +2110,7 @@ static int main_graphical(Scene& scene) { std::array software_renderer_buf_device_mems; std::array software_renderer_buf_mems; - auto destroy_software_renderer_bufs = [&]() { + auto destroy_software_renderer_bufs = [&] { for (size_t i = max_frames_in_flight; i > 0; i--) { vkUnmapMemory(device, software_renderer_buf_device_mems[i - 1]); vkFreeMemory(device, software_renderer_buf_device_mems[i - 1], nullptr); @@ -2095,7 +2118,7 @@ static int main_graphical(Scene& scene) { } }; - auto recreate_software_renderer_bufs = [&]() { + auto recreate_software_renderer_bufs = [&] { if (!first_software_renderer_buf_creation) { destroy_software_renderer_bufs(); if (software_renderer.width() != swapchain_extent.width || software_renderer.height() != swapchain_extent.height) @@ -2125,7 +2148,7 @@ static int main_graphical(Scene& scene) { scene_main(Matrix4::idty(), scene, // update_surface_size - [&]() { + [&] { return std::tuple { swapchain_extent.width, swapchain_extent.height }; }, @@ -2219,7 +2242,7 @@ static int main_graphical(Scene& scene) { }, // render_and_present_frame - [&](const Matrix4& view_mat, const Matrix4& proj_mat, float /* time */, float ellapsed_time) { + [&](const Matrix4& view_mat, const Matrix4& proj_mat, const Matrix4& inv_view_mat, float /* time */, float ellapsed_time) { if (show_fps) std::cout << "\rfps: " << (1.f / ellapsed_time) << " "; @@ -2246,9 +2269,6 @@ static int main_graphical(Scene& scene) { } } - // TODO: this is where we set uniform buffers for the hardware renderer, and where we - // render for the software renderer. We should do approximately the same thing in the - // same place for both renderers switch (renderer_mode) { case GraphicalRendererMode::hardware: { @@ -2256,20 +2276,24 @@ static int main_graphical(Scene& scene) { for (size_t i = 0; i < scene.objs.size(); i++) { // TODO: should use push constants engine::vk::UniformBufferObject ubo { - .model = scene.objs[i].transform.to_mat4(), - .view = view_mat, - .proj = proj_mat, - .camera_rot = Matrix4::from_quaternion(scene.camera.transform.rot), - .camera_loc = scene.camera.transform.loc, + .model = scene.objs[i].transform.to_mat4(), + .view = view_mat, + .proj = proj_mat, + .inv_view = inv_view_mat, }; memcpy(uniform_buf_mems[frame_idx * scene.objs.size() + i], &ubo, sizeof(engine::vk::UniformBufferObject)); } } break; + case GraphicalRendererMode::software: + break; + } + + switch (renderer_mode) { + case GraphicalRendererMode::hardware: + break; case GraphicalRendererMode::software: { - // TODO: this is a copy-paste of the code in render_software, which is obviously - // bad auto proj_view_mat = proj_mat * view_mat; software_renderer.clear(); for (const auto& obj : scene.objs) { @@ -2277,17 +2301,27 @@ static int main_graphical(Scene& scene) { auto final_mat = proj_view_mat * model_mat; const auto& mesh = obj.mesh; std::vector vertices; + std::vector normals; std::vector vertices_data; for (const auto& vertex : mesh.vertices) { - vertices.push_back(final_mat * Vector4 { vertex, 1.f }); - vertices_data.push_back(VertexData((model_mat * vertex).xyz())); + Vector4 vertex4 { vertex, 1.f }; + vertices.push_back(final_mat * vertex4); + vertices_data.push_back(VertexData((model_mat * vertex4).xyz())); } + for (const auto& normal : mesh.normals) + normals.push_back((model_mat * Vector4 { normal, 0.f }).xyz()); for (const auto& triangle_indices : mesh.indices) { - [&](std::integer_sequence) { - software_renderer.draw_triangle( - {{vertices[triangle_indices[j][0]], mesh.normals[triangle_indices[j][1]], vertices_data[triangle_indices[j][0]]}...} - ); - }(std::make_integer_sequence()); + software_renderer.draw_triangle([&](std::index_sequence) constexpr -> engine::o3d::Triangle { + return { + { + vertices[triangle_indices[j][0]], + normals [triangle_indices[j][1]], + mesh.uvs[triangle_indices[j][2]], + vertices_data[triangle_indices[j][0]] + } + ... + }; + }(std::make_index_sequence<3>())); } } memcpy(software_renderer_buf_mems[frame_idx], software_renderer.fb.pixels(), swapchain_extent.width * swapchain_extent.height * 4); @@ -2380,7 +2414,7 @@ static int main_graphical(Scene& scene) { } { - VkClearValue clear_color_val { .color { .float32 = { 0.f, 0.f, 0.f, 1.f } } }; + VkClearValue clear_color_val { .color { .float32 = { 0.f, 0.f, 0.f, (transparent_window ? 0.f : 1.f) } } }; VkClearValue clear_depth_val { .depthStencil { .depth = 1.f, .stencil = 0 } }; VkRenderingAttachmentInfo rendering_color_info { .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, @@ -2760,6 +2794,17 @@ int main(int argc, char *argv[]) { } }, }; + case GameType::test: + return { + { + engine::parse_object(DATADIR "/assets/viking_room.obj"), + { + Vector3(0.f, .5f, 0.f), + Quaternion::look_towards({ -1.f, 0.f, 0.f }, { 0.f, 0.f, 1.f }).conjugate(), + Vector3(1.f, 1.f, 1.f), + } + }, + }; } std::unreachable(); }() -- cgit v1.2.3