From d7d79214a93bc96b38ac018aad4c8d5ee88d51ca Mon Sep 17 00:00:00 2001 From: Frederico Linhares Date: Tue, 27 Sep 2022 17:38:20 -0300 Subject: feat Allow multiple textures to be used with the same mesh --- src/vk/graphics_pipeline_3d.cpp | 7 +- src/vk/mesh.cpp | 161 ++++++++++++++++++++++++++++++++++++ src/vk/mesh.hpp | 48 +++++++++++ src/vk/model.cpp | 177 +++++++--------------------------------- src/vk/model.hpp | 22 +---- 5 files changed, 247 insertions(+), 168 deletions(-) create mode 100644 src/vk/mesh.cpp create mode 100644 src/vk/mesh.hpp (limited to 'src/vk') diff --git a/src/vk/graphics_pipeline_3d.cpp b/src/vk/graphics_pipeline_3d.cpp index eb86401..f3a54e7 100644 --- a/src/vk/graphics_pipeline_3d.cpp +++ b/src/vk/graphics_pipeline_3d.cpp @@ -566,7 +566,7 @@ GraphicsPipeline3D::draw( this->descriptor_sets_world[image_index], view->descriptor_sets_3d[image_index], model->descriptor_sets[image_index]}; - VkBuffer vertex_buffers[]{model->vertex_buffer->buffer}; + VkBuffer vertex_buffers[]{model->mesh->vertex_buffer->buffer}; VkDeviceSize offsets[]{0}; vkCmdBindDescriptorSets( @@ -579,10 +579,11 @@ GraphicsPipeline3D::draw( vkCmdBindVertexBuffers( draw_command_buffer, 0, 1, vertex_buffers, offsets); vkCmdBindIndexBuffer( - draw_command_buffer, model->index_buffer->buffer, 0, + draw_command_buffer, model->mesh->index_buffer->buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdDrawIndexed( - draw_command_buffer, model->index_count, instances.size(), 0, 0, 0); + draw_command_buffer, model->mesh->index_count, instances.size(), + 0, 0, 0); } VK::UBOModelInstance ubo_model_instance; diff --git a/src/vk/mesh.cpp b/src/vk/mesh.cpp new file mode 100644 index 0000000..70b9d45 --- /dev/null +++ b/src/vk/mesh.cpp @@ -0,0 +1,161 @@ +/* + * Copyright 2022 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mesh.hpp" + +#include +#include + +#include "../command.hpp" +#include "../core.hpp" +#include "vertex_3d.hpp" + +namespace +{ + +// Data that is only needed for the command chain but not for the Mesh goes +// here. +struct MeshBuilder +{ + std::string mesh_path; + VK::Mesh *mesh; + + MeshBuilder(VK::Mesh *m, std::string mp); + MeshBuilder(VK::Mesh *m, const char* mp); +}; + +MeshBuilder::MeshBuilder(VK::Mesh *m, std::string mp): + mesh{m}, + mesh_path{mp} +{ +} + +MeshBuilder::MeshBuilder(VK::Mesh *m, const char *mp): + MeshBuilder{m, std::string(mp)} +{ +} + +uint32_t read_uint32_from_file(std::ifstream &input_file) +{ + uint32_t data{}; + input_file.read((char*)&data, sizeof(uint32_t)); + return data; +} + +glm::vec2 read_vec2_from_file(std::ifstream &input_file) +{ + glm::vec2 data{}; + input_file.read((char*)&data.x, sizeof(glm::vec2::value_type)); + input_file.read((char*)&data.y, sizeof(glm::vec2::value_type)); + return data; +} + +glm::vec3 read_vec3_from_file(std::ifstream &input_file) +{ + glm::vec3 data{}; + input_file.read((char*)&data.x, sizeof(glm::vec3::value_type)); + input_file.read((char*)&data.y, sizeof(glm::vec3::value_type)); + input_file.read((char*)&data.z, sizeof(glm::vec3::value_type)); + return data; +} + +void +load_mesh(void *obj) +{ + auto self = static_cast(obj); + + std::ifstream input_file{self->mesh_path}; + if(!input_file.is_open()) throw CommandError{"Failed to open file."}; + + self->mesh->queue_family = + cg_core.vk_device_with_swapchain->get_queue_family_with_graphics(); + + // Load vertexes. + { + auto vertex_count{read_uint32_from_file(input_file)}; + std::vector vertexes{vertex_count}; + + for(auto i{0}; i < vertex_count; i++) + { + vertexes[i].position = read_vec3_from_file(input_file); + vertexes[i].normal = read_vec3_from_file(input_file); + vertexes[i].texture_coord = read_vec2_from_file(input_file); + } + + void *vertexes_data{vertexes.data()}; + size_t vertexes_size = sizeof(vertexes[0]) * vertexes.size(); + self->mesh->source_vertex_buffer = new VK::SourceBuffer{ + self->mesh->queue_family->device, vertexes_data, vertexes_size}; + self->mesh->vertex_buffer = new VK::DestinationBuffer{ + self->mesh->queue_family, self->mesh->source_vertex_buffer, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT}; + } + + // Load indexes. + { + self->mesh->index_count = read_uint32_from_file(input_file); + std::vector indexes(self->mesh->index_count); + + for(auto i{0}; i < self->mesh->index_count; i++) + indexes[i] = read_uint32_from_file(input_file); + + void *indexes_data{indexes.data()}; + size_t indexes_size{sizeof(indexes[0]) * indexes.size()}; + VK::SourceBuffer source_index_buffer{ + self->mesh->queue_family->device, indexes_data, indexes_size}; + self->mesh->index_buffer = new VK::DestinationBuffer{ + self->mesh->queue_family, &source_index_buffer, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT}; + } +} + +void +unload_mesh(void *obj) +{ + auto self = static_cast(obj); + + delete self->mesh->index_buffer; + delete self->mesh->vertex_buffer; + delete self->mesh->source_vertex_buffer; +} + +static const CommandChain loader{ + {&load_mesh, &unload_mesh} +}; + +} + +namespace VK +{ + +Mesh::Mesh(std::string mesh_path) +{ + MeshBuilder mesh_builder(this, mesh_path); + loader.execute(&mesh_builder); +} + +Mesh::Mesh(const char* mesh_path): + Mesh{std::string(mesh_path)} +{ +} + +Mesh::~Mesh() +{ + MeshBuilder mesh_builder(this, ""); + loader.revert(&mesh_builder); +} + +} diff --git a/src/vk/mesh.hpp b/src/vk/mesh.hpp new file mode 100644 index 0000000..97b9d8a --- /dev/null +++ b/src/vk/mesh.hpp @@ -0,0 +1,48 @@ +/* + * Copyright 2022 Frederico de Oliveira Linhares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CANDY_GEAR_VK_MESH_H +#define CANDY_GEAR_VK_MESH_H 1 + +#include +#include + +#include "core.hpp" +#include "destination_buffer.hpp" +#include "queue_family.hpp" +#include "uniform_buffer.hpp" +#include "texture.hpp" + +namespace VK +{ + +struct Mesh +{ + QueueFamily *queue_family; + + uint32_t index_count; + SourceBuffer *source_vertex_buffer; + DestinationBuffer *index_buffer; + DestinationBuffer *vertex_buffer; + + Mesh(std::string mesh_path); + Mesh(const char* mesh_path); + ~Mesh(); +}; + +} + +#endif /* CANDY_GEAR_VK_MESH_H */ diff --git a/src/vk/model.cpp b/src/vk/model.cpp index b92ec91..d38342d 100644 --- a/src/vk/model.cpp +++ b/src/vk/model.cpp @@ -17,181 +17,71 @@ #include "model.hpp" #include -#include -#include "../command.hpp" #include "../core.hpp" -#include "vertex_3d.hpp" namespace { -// Data that is only needed for the command chain but not for the Model goes -// here. -struct ModelBuilder -{ - std::string model_path; - VK::Model *model; - - ModelBuilder(VK::Model *m, std::string mp); - ModelBuilder(VK::Model *m, const char* mp); -}; - -ModelBuilder::ModelBuilder(VK::Model *m, std::string mp): - model{m}, - model_path{mp} -{ -} - -ModelBuilder::ModelBuilder(VK::Model *m, const char *mp): - ModelBuilder{m, std::string(mp)} -{ -} - -uint32_t read_uint32_from_file(std::ifstream &input_file) -{ - uint32_t data{}; - input_file.read((char*)&data, sizeof(uint32_t)); - return data; -} - -glm::vec2 read_vec2_from_file(std::ifstream &input_file) -{ - glm::vec2 data{}; - input_file.read((char*)&data.x, sizeof(glm::vec2::value_type)); - input_file.read((char*)&data.y, sizeof(glm::vec2::value_type)); - return data; -} - -glm::vec3 read_vec3_from_file(std::ifstream &input_file) -{ - glm::vec3 data{}; - input_file.read((char*)&data.x, sizeof(glm::vec3::value_type)); - input_file.read((char*)&data.y, sizeof(glm::vec3::value_type)); - input_file.read((char*)&data.z, sizeof(glm::vec3::value_type)); - return data; -} - -void -load_mesh(void *obj) -{ - auto self = static_cast(obj); - - std::ifstream input_file{self->model_path}; - if(!input_file.is_open()) throw CommandError{"Failed to open file."}; - - self->model->queue_family = - cg_core.vk_device_with_swapchain->get_queue_family_with_graphics(); - - // Load vertexes. - { - auto vertex_count{read_uint32_from_file(input_file)}; - std::vector vertexes{vertex_count}; - - for(auto i{0}; i < vertex_count; i++) - { - vertexes[i].position = read_vec3_from_file(input_file); - vertexes[i].normal = read_vec3_from_file(input_file); - vertexes[i].texture_coord = read_vec2_from_file(input_file); - } - - void *vertexes_data{vertexes.data()}; - size_t vertexes_size = sizeof(vertexes[0]) * vertexes.size(); - self->model->source_vertex_buffer = new VK::SourceBuffer{ - self->model->queue_family->device, vertexes_data, vertexes_size}; - self->model->vertex_buffer = new VK::DestinationBuffer{ - self->model->queue_family, self->model->source_vertex_buffer, - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT}; - } - - // Load indexes. - { - self->model->index_count = read_uint32_from_file(input_file); - std::vector indexes(self->model->index_count); - - for(auto i{0}; i < self->model->index_count; i++) - indexes[i] = read_uint32_from_file(input_file); - - void *indexes_data{indexes.data()}; - size_t indexes_size{sizeof(indexes[0]) * indexes.size()}; - VK::SourceBuffer source_index_buffer{ - self->model->queue_family->device, indexes_data, indexes_size}; - self->model->index_buffer = new VK::DestinationBuffer{ - self->model->queue_family, &source_index_buffer, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT}; - } -} - -void -unload_mesh(void *obj) -{ - auto self = static_cast(obj); - - delete self->model->index_buffer; - delete self->model->vertex_buffer; - delete self->model->source_vertex_buffer; -} - void load_uniform_buffers(void *obj) { - auto self = static_cast(obj); + auto self = static_cast(obj); - self->model->ub_model_instance.reserve(cg_core.vk_swapchain->images_count); + self->ub_model_instance.reserve(cg_core.vk_swapchain->images_count); for(int i{0}; i < cg_core.vk_swapchain->images_count; i++) - self->model->ub_model_instance.emplace_back( + self->ub_model_instance.emplace_back( cg_core.vk_device_with_swapchain, sizeof(VK::UBOModelInstance)); } void unload_uniform_buffers(void *obj) { - auto self = static_cast(obj); + auto self = static_cast(obj); - self->model->ub_model_instance.clear(); + self->ub_model_instance.clear(); } void load_descriptor_set_pool(void *obj) { - auto self = static_cast(obj); + auto self = static_cast(obj); std::array descriptor_pool_sizes{}; descriptor_pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; descriptor_pool_sizes[0].descriptorCount = - self->model->ub_model_instance.size(); + self->ub_model_instance.size(); descriptor_pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptor_pool_sizes[1].descriptorCount = - self->model->ub_model_instance.size(); + self->ub_model_instance.size(); VkDescriptorPoolCreateInfo pool_info{}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.pNext = nullptr; pool_info.flags = 0; - pool_info.maxSets = self->model->ub_model_instance.size(); + pool_info.maxSets = self->ub_model_instance.size(); pool_info.poolSizeCount = descriptor_pool_sizes.size(); pool_info.pPoolSizes = descriptor_pool_sizes.data(); if(vkCreateDescriptorPool( - self->model->queue_family->device->device, &pool_info, nullptr, - &self->model->descriptor_pool) != VK_SUCCESS) + self->mesh->queue_family->device->device, &pool_info, nullptr, + &self->descriptor_pool) != VK_SUCCESS) throw CommandError{"Failed to create a Vulkan descriptor pool."}; } void unload_descriptor_set_pool(void *obj) { - auto self = static_cast(obj); + auto self = static_cast(obj); vkDestroyDescriptorPool( - self->model->queue_family->device->device, self->model->descriptor_pool, - nullptr); + self->mesh->queue_family->device->device, self->descriptor_pool, nullptr); } void load_descriptor_sets(void *obj) { - auto self = static_cast(obj); + auto self = static_cast(obj); std::vector layouts( cg_core.vk_swapchain->images_count, @@ -199,37 +89,37 @@ load_descriptor_sets(void *obj) VkDescriptorSetAllocateInfo alloc_info{}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorPool = self->model->descriptor_pool; + alloc_info.descriptorPool = self->descriptor_pool; alloc_info.descriptorSetCount = layouts.size(); alloc_info.pSetLayouts = layouts.data(); - self->model->descriptor_sets.resize(layouts.size()); + self->descriptor_sets.resize(layouts.size()); if(vkAllocateDescriptorSets( - self->model->queue_family->device->device, &alloc_info, - self->model->descriptor_sets.data()) != VK_SUCCESS) + self->mesh->queue_family->device->device, &alloc_info, + self->descriptor_sets.data()) != VK_SUCCESS) CommandError{"Failed to create Vulkan descriptor set."}; } void load_buffers_to_descriptor_sets(void *obj) { - auto self = static_cast(obj); + auto self = static_cast(obj); - for(auto i{0}; i < self->model->ub_model_instance.size(); i++) + for(auto i{0}; i < self->ub_model_instance.size(); i++) { VkDescriptorBufferInfo buffer_info{}; - buffer_info.buffer = self->model->ub_model_instance[i].buffer; + buffer_info.buffer = self->ub_model_instance[i].buffer; buffer_info.offset = 0; buffer_info.range = sizeof(VK::UBOModelInstance); VkDescriptorImageInfo image_info{}; image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - image_info.imageView = self->model->texture->view; - image_info.sampler = self->model->texture->sampler; + image_info.imageView = self->texture->view; + image_info.sampler = self->texture->sampler; std::array write_descriptors{}; write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_descriptors[0].dstSet = self->model->descriptor_sets[i]; + write_descriptors[0].dstSet = self->descriptor_sets[i]; write_descriptors[0].dstBinding = 0; write_descriptors[0].dstArrayElement = 0; write_descriptors[0].descriptorCount = 1; @@ -239,7 +129,7 @@ load_buffers_to_descriptor_sets(void *obj) write_descriptors[0].pTexelBufferView = nullptr; write_descriptors[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_descriptors[1].dstSet = self->model->descriptor_sets[i]; + write_descriptors[1].dstSet = self->descriptor_sets[i]; write_descriptors[1].dstBinding = 1; write_descriptors[1].dstArrayElement = 0; write_descriptors[1].descriptorCount = 1; @@ -256,11 +146,10 @@ load_buffers_to_descriptor_sets(void *obj) } static const CommandChain loader{ - {&load_mesh, &unload_mesh}, {&load_uniform_buffers, &unload_uniform_buffers}, {&load_descriptor_set_pool, &unload_descriptor_set_pool}, {&load_descriptor_sets, nullptr}, - {&load_buffers_to_descriptor_sets, nullptr}, + {&load_buffers_to_descriptor_sets, nullptr} }; } @@ -268,22 +157,16 @@ static const CommandChain loader{ namespace VK { -Model::Model(std::string model_path, std::shared_ptr texture): +Model::Model(std::shared_ptr mesh, std::shared_ptr texture): + mesh{mesh}, texture{texture} { - ModelBuilder model_builder(this, model_path); - loader.execute(&model_builder); -} - -Model::Model(const char* model_path, std::shared_ptr texture): - Model{std::string(model_path), texture} -{ + loader.execute(this); } Model::~Model() { - ModelBuilder model_builder(this, ""); - loader.revert(&model_builder); + loader.revert(this); } } diff --git a/src/vk/model.hpp b/src/vk/model.hpp index d6f8b69..72682b2 100644 --- a/src/vk/model.hpp +++ b/src/vk/model.hpp @@ -17,13 +17,7 @@ #ifndef CANDY_GEAR_VK_MODEL_H #define CANDY_GEAR_VK_MODEL_H 1 -#include -#include - -#include "core.hpp" -#include "destination_buffer.hpp" -#include "queue_family.hpp" -#include "uniform_buffer.hpp" +#include "mesh.hpp" #include "texture.hpp" namespace VK @@ -31,22 +25,14 @@ namespace VK struct Model { - QueueFamily *queue_family; - - uint32_t index_count; - SourceBuffer *source_vertex_buffer; - DestinationBuffer *index_buffer; - DestinationBuffer *vertex_buffer; + std::shared_ptr mesh; + std::shared_ptr texture; std::vector ub_model_instance; - VkDescriptorPool descriptor_pool; std::vector descriptor_sets; - std::shared_ptr texture; - - Model(std::string model_path, std::shared_ptr texture); - Model(const char* model_path, std::shared_ptr texture); + Model(std::shared_ptr mesh, std::shared_ptr texture); ~Model(); }; -- cgit v1.2.3