diff --git a/.cache/clangd/index/buffers.h.CC15E40B6084C10D.idx b/.cache/clangd/index/buffers.h.CC15E40B6084C10D.idx index 19a2916..80de00b 100644 Binary files a/.cache/clangd/index/buffers.h.CC15E40B6084C10D.idx and b/.cache/clangd/index/buffers.h.CC15E40B6084C10D.idx differ diff --git a/.cache/clangd/index/devicelibrary.cpp.A6A50BF3BD186A09.idx b/.cache/clangd/index/devicelibrary.cpp.A6A50BF3BD186A09.idx index f13b3c9..1aa5d88 100644 Binary files a/.cache/clangd/index/devicelibrary.cpp.A6A50BF3BD186A09.idx and b/.cache/clangd/index/devicelibrary.cpp.A6A50BF3BD186A09.idx differ diff --git a/.cache/clangd/index/entrypoint.cpp.9286A9B0BD8A276E.idx b/.cache/clangd/index/entrypoint.cpp.9286A9B0BD8A276E.idx index b8608c4..57a90d7 100644 Binary files a/.cache/clangd/index/entrypoint.cpp.9286A9B0BD8A276E.idx and b/.cache/clangd/index/entrypoint.cpp.9286A9B0BD8A276E.idx differ diff --git a/.cache/clangd/index/model.h.C3ECCCBE7C04E4C8.idx b/.cache/clangd/index/model.h.C3ECCCBE7C04E4C8.idx index 763a7c1..0d3b331 100644 Binary files a/.cache/clangd/index/model.h.C3ECCCBE7C04E4C8.idx and b/.cache/clangd/index/model.h.C3ECCCBE7C04E4C8.idx differ diff --git a/imgui.ini b/imgui.ini index ca80a3a..ff29567 100644 --- a/imgui.ini +++ b/imgui.ini @@ -3,6 +3,6 @@ Pos=60,60 Size=400,400 [Window][Agnosia Debug] -Pos=40,377 +Pos=59,322 Size=623,438 diff --git a/src/entrypoint.cpp b/src/entrypoint.cpp index b296faf..5946517 100644 --- a/src/entrypoint.cpp +++ b/src/entrypoint.cpp @@ -87,8 +87,7 @@ void createInstance() { throw std::runtime_error("failed to create instance!"); } } - -void initVulkan() { +void initAgnosia() { Material *vikingRoomMaterial = new Material("vikingRoomMaterial", "assets/textures/viking_room.png"); Material *stanfordDragonMaterial = @@ -104,7 +103,8 @@ void initVulkan() { Model *teapot = new Model("teapot", *teapotMaterial, "assets/models/teapot.obj", glm::vec3(1.0f, -3.0f, -1.0f)); - +} +void initVulkan() { // Initialize volk and continue if successful. volkInitialize(); // Initialize vulkan and set up pipeline. @@ -122,9 +122,7 @@ void initVulkan() { Graphics::createCommandPool(); // Image creation MUST be after command pool, because command // buffers. - vikingRoom->populateData(); - stanfordDragon->populateData(); - teapot->populateData(); + Model::populateModels(); Texture::createMaterialTextures(Model::getInstances()); Texture::createColorResources(); Texture::createDepthResources(); @@ -150,6 +148,11 @@ void mainLoop() { void cleanup() { Render::cleanupSwapChain(); Graphics::destroyGraphicsPipeline(); + Buffers::destroyDescriptorPool(); + Model::destroyTextures(); + + vkDestroyDescriptorSetLayout(DeviceControl::getDevice(), + Buffers::getDescriptorSetLayout(), nullptr); Buffers::destroyBuffers(); Render::destroyFenceSemaphores(); @@ -179,6 +182,7 @@ GLFWwindow *EntryApp::getWindow() { return window; } void EntryApp::run() { initWindow(); + initAgnosia(); initVulkan(); mainLoop(); cleanup(); diff --git a/src/graphics/buffers.cpp b/src/graphics/buffers.cpp index 78af9a7..a808344 100644 --- a/src/graphics/buffers.cpp +++ b/src/graphics/buffers.cpp @@ -122,6 +122,9 @@ void Buffers::createDescriptorPool() { throw std::runtime_error("failed to create descriptor pool!"); } } +void Buffers::destroyDescriptorPool() { + vkDestroyDescriptorPool(DeviceControl::getDevice(), descriptorPool, nullptr); +} void Buffers::createDescriptorSet(std::vector models) { VkDescriptorSetAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; diff --git a/src/graphics/buffers.h b/src/graphics/buffers.h index be65a6d..33f308b 100644 --- a/src/graphics/buffers.h +++ b/src/graphics/buffers.h @@ -19,6 +19,7 @@ public: static void createDescriptorSetLayout(); static void createDescriptorSet(std::vector models); static void createDescriptorPool(); + static void destroyDescriptorPool(); static void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags props, VkBuffer &buffer, VkDeviceMemory &bufferMemory); diff --git a/src/graphics/model.cpp b/src/graphics/model.cpp index 3a39550..64b3376 100644 --- a/src/graphics/model.cpp +++ b/src/graphics/model.cpp @@ -20,15 +20,21 @@ std::vector Model::instances; VmaAllocator _allocator; +// chatgpt did this and the haters can WEEP fuck hash functions. namespace std { template <> struct hash { size_t operator()(Agnosia_T::Vertex const &vertex) const { - return ((hash()(vertex.pos) ^ - (hash()(vertex.color) << 1)) >> - 1) ^ - (hash()(vertex.texCoord) << 1); + size_t hashPos = hash()(vertex.pos); + size_t hashColor = hash()(vertex.color); + size_t hashUV = hash()(vertex.uv); + size_t hashNormal = hash()(vertex.normal); + + // Combine all hashes + return ((hashPos ^ (hashColor << 1)) >> 1) ^ (hashUV << 1) ^ + (hashNormal << 2); } }; + } // namespace std void Model::createMemoryAllocator(VkInstance vkInstance) { VmaVulkanFunctions vulkanFuncs{ @@ -105,112 +111,128 @@ Model::Model(const std::string &modelID, const Material &material, instances.push_back(this); } -void Model::populateData() { +void Model::populateModels() { + for (Model *model : getInstances()) { - std::vector vertices; - // Index buffer definition, showing which points to reuse. - std::vector indices; - tinyobj::ObjReaderConfig readerConfig; - tinyobj::ObjReader reader; + std::vector vertices; + // Index buffer definition, showing which points to reuse. + std::vector indices; + tinyobj::ObjReaderConfig readerConfig; + tinyobj::ObjReader reader; - if (!reader.ParseFromFile(modelPath, readerConfig)) { - if (!reader.Error().empty()) { - throw std::runtime_error(reader.Error()); - } - if (!reader.Warning().empty()) { - throw std::runtime_error(reader.Warning()); - } - } - - auto &attrib = reader.GetAttrib(); - auto &shapes = reader.GetShapes(); - auto &materials = reader.GetMaterials(); - - std::unordered_map uniqueVertices{}; - - for (const auto &shape : shapes) { - for (const auto &index : shape.mesh.indices) { - Agnosia_T::Vertex vertex{}; - - vertex.pos = {attrib.vertices[3 * index.vertex_index + 0], - attrib.vertices[3 * index.vertex_index + 1], - attrib.vertices[3 * index.vertex_index + 2]}; - - // TODO: Small fix here, handle if there are no UV's unwrapped for the - // model. - // As of now, if it is not unwrapped, it segfaults on texCoord - // assignment. Obviously we should always have UV's, but it - // shouldn't crash, just unwrap in a default method. - vertex.texCoord = {attrib.texcoords[2 * index.texcoord_index + 0], - 1.0f - attrib.texcoords[2 * index.texcoord_index + 1]}; - vertex.color = {1.0f, 1.0f, 1.0f}; - - if (uniqueVertices.count(vertex) == 0) { - uniqueVertices[vertex] = static_cast(vertices.size()); - vertices.push_back(vertex); + if (!reader.ParseFromFile(model->modelPath, readerConfig)) { + if (!reader.Error().empty()) { + throw std::runtime_error(reader.Error()); + } + if (!reader.Warning().empty()) { + throw std::runtime_error(reader.Warning()); } - indices.push_back(uniqueVertices[vertex]); } + + auto &attrib = reader.GetAttrib(); + auto &shapes = reader.GetShapes(); + auto &materials = reader.GetMaterials(); + + std::unordered_map uniqueVertices{}; + + for (const auto &shape : shapes) { + for (const auto &index : shape.mesh.indices) { + Agnosia_T::Vertex vertex{}; + + vertex.pos = {attrib.vertices[3 * index.vertex_index + 0], + attrib.vertices[3 * index.vertex_index + 1], + attrib.vertices[3 * index.vertex_index + 2]}; + + vertex.normal = {attrib.normals[3 * index.normal_index + 0], + attrib.normals[3 * index.normal_index + 1], + attrib.normals[3 * index.normal_index + 2]}; + // TODO: Small fix here, handle if there are no UV's unwrapped for the + // model. + // As of now, if it is not unwrapped, it segfaults on texCoord + // assignment. Obviously we should always have UV's, but it + // shouldn't crash, just unwrap in a default method. + vertex.uv = {attrib.texcoords[2 * index.texcoord_index + 0], + 1.0f - attrib.texcoords[2 * index.texcoord_index + 1]}; + vertex.color = {1.0f, 1.0f, 1.0f}; + + if (uniqueVertices.count(vertex) == 0) { + uniqueVertices[vertex] = static_cast(vertices.size()); + vertices.push_back(vertex); + } + indices.push_back(uniqueVertices[vertex]); + } + } + + const size_t vertexBufferSize = vertices.size() * sizeof(Agnosia_T::Vertex); + const size_t indexBufferSize = indices.size() * sizeof(uint32_t); + + Agnosia_T::GPUMeshBuffers newSurface; + + // Create a Vertex Buffer here, infinitely easier than the old Vulkan + // method! + newSurface.vertexBuffer = createBuffer( + vertexBufferSize, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + VMA_MEMORY_USAGE_GPU_ONLY); + // Find the address of the vertex buffer! + VkBufferDeviceAddressInfo deviceAddressInfo{ + .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + .buffer = newSurface.vertexBuffer.buffer, + }; + newSurface.vertexBufferAddress = vkGetBufferDeviceAddress( + DeviceControl::getDevice(), &deviceAddressInfo); + + // Create the index buffer to iterate over and check for duplicate vertices + newSurface.indexBuffer = createBuffer(indexBufferSize, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VMA_MEMORY_USAGE_GPU_ONLY); + + Agnosia_T::AllocatedBuffer stagingBuffer = createBuffer( + vertexBufferSize + indexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VMA_MEMORY_USAGE_CPU_ONLY); + + void *data = stagingBuffer.allocation->GetMappedData(); + + // Copy the vertex buffer + memcpy(data, vertices.data(), vertexBufferSize); + // Copy the index buffer + memcpy((char *)data + vertexBufferSize, indices.data(), indexBufferSize); + + immediate_submit([&](VkCommandBuffer cmd) { + VkBufferCopy vertexCopy{0}; + vertexCopy.dstOffset = 0; + vertexCopy.srcOffset = 0; + vertexCopy.size = vertexBufferSize; + + vkCmdCopyBuffer(cmd, stagingBuffer.buffer, newSurface.vertexBuffer.buffer, + 1, &vertexCopy); + + VkBufferCopy indexCopy{0}; + indexCopy.dstOffset = 0; + indexCopy.srcOffset = vertexBufferSize; + indexCopy.size = indexBufferSize; + + vkCmdCopyBuffer(cmd, stagingBuffer.buffer, newSurface.indexBuffer.buffer, + 1, &indexCopy); + }); + vmaDestroyBuffer(_allocator, stagingBuffer.buffer, + stagingBuffer.allocation); + + model->buffers = newSurface; + model->indiceCount = indices.size(); + } +} +void Model::destroyTextures() { + for (Model *model : Model::getInstances()) { + vkDestroySampler(DeviceControl::getDevice(), + model->getMaterial().getTextureSampler(), nullptr); + vkDestroyImageView(DeviceControl::getDevice(), + model->getMaterial().getTextureView(), nullptr); + vkDestroyImage(DeviceControl::getDevice(), + model->getMaterial().getTextureImage(), nullptr); } - - const size_t vertexBufferSize = vertices.size() * sizeof(Agnosia_T::Vertex); - const size_t indexBufferSize = indices.size() * sizeof(uint32_t); - - Agnosia_T::GPUMeshBuffers newSurface; - - // Create a Vertex Buffer here, infinitely easier than the old Vulkan method! - newSurface.vertexBuffer = createBuffer( - vertexBufferSize, - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, - VMA_MEMORY_USAGE_GPU_ONLY); - // Find the address of the vertex buffer! - VkBufferDeviceAddressInfo deviceAddressInfo{ - .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, - .buffer = newSurface.vertexBuffer.buffer, - }; - newSurface.vertexBufferAddress = - vkGetBufferDeviceAddress(DeviceControl::getDevice(), &deviceAddressInfo); - - // Create the index buffer to iterate over and check for duplicate vertices - newSurface.indexBuffer = createBuffer(indexBufferSize, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VMA_MEMORY_USAGE_GPU_ONLY); - - Agnosia_T::AllocatedBuffer stagingBuffer = - createBuffer(vertexBufferSize + indexBufferSize, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); - - void *data = stagingBuffer.allocation->GetMappedData(); - - // Copy the vertex buffer - memcpy(data, vertices.data(), vertexBufferSize); - // Copy the index buffer - memcpy((char *)data + vertexBufferSize, indices.data(), indexBufferSize); - - immediate_submit([&](VkCommandBuffer cmd) { - VkBufferCopy vertexCopy{0}; - vertexCopy.dstOffset = 0; - vertexCopy.srcOffset = 0; - vertexCopy.size = vertexBufferSize; - - vkCmdCopyBuffer(cmd, stagingBuffer.buffer, newSurface.vertexBuffer.buffer, - 1, &vertexCopy); - - VkBufferCopy indexCopy{0}; - indexCopy.dstOffset = 0; - indexCopy.srcOffset = vertexBufferSize; - indexCopy.size = indexBufferSize; - - vkCmdCopyBuffer(cmd, stagingBuffer.buffer, newSurface.indexBuffer.buffer, 1, - &indexCopy); - }); - vmaDestroyBuffer(_allocator, stagingBuffer.buffer, stagingBuffer.allocation); - - this->buffers = newSurface; - this->objPosition = objPosition; - this->indiceCount = indices.size(); } std::string Model::getID() { return this->ID; } diff --git a/src/graphics/model.h b/src/graphics/model.h index d2bdd0f..0feeadc 100644 --- a/src/graphics/model.h +++ b/src/graphics/model.h @@ -28,7 +28,8 @@ public: static void createMemoryAllocator(VkInstance instance); static const std::vector &getInstances(); - void populateData(); + static void populateModels(); + static void destroyTextures(); Agnosia_T::GPUMeshBuffers getBuffers(); std::string getID(); diff --git a/src/shaders/common.glsl b/src/shaders/common.glsl index f117a1d..2448db0 100644 --- a/src/shaders/common.glsl +++ b/src/shaders/common.glsl @@ -4,6 +4,7 @@ struct Vertex { vec3 pos; + vec3 normal; vec3 color; vec2 texCoord; }; diff --git a/src/shaders/fragment.frag b/src/shaders/fragment.frag index 27d6329..65dfb87 100644 --- a/src/shaders/fragment.frag +++ b/src/shaders/fragment.frag @@ -11,5 +11,5 @@ layout(location = 1) in vec2 fragTexCoord; layout(location = 0) out vec4 outColor; void main() { - outColor = texture(texSampler[PushConstants.textureID], fragTexCoord); + outColor = texture(texSampler[PushConstants.textureID], fragTexCoord) * vec4(fragColor, 1.0f); } diff --git a/src/types.h b/src/types.h index 5108fc4..e824c42 100644 --- a/src/types.h +++ b/src/types.h @@ -10,12 +10,13 @@ public: // This defines what a vertex is! // We control the position, color and texture coordinate here! glm::vec3 pos; + glm::vec3 normal; glm::vec3 color; - glm::vec2 texCoord; + glm::vec2 uv; bool operator==(const Vertex &other) const { - return pos == other.pos && color == other.color && - texCoord == other.texCoord; + return pos == other.pos && normal == other.normal && + color == other.color && uv == other.uv; } }; struct AllocatedBuffer {