diff --git a/src/engine/vk/VkImage.cpp b/src/engine/vk/VkImage.cpp index bdc7dbb..0cf938d 100644 --- a/src/engine/vk/VkImage.cpp +++ b/src/engine/vk/VkImage.cpp @@ -12,12 +12,12 @@ namespace Vixen::Vk { const uint8_t mipLevels ) : device(device), allocation(VK_NULL_HANDLE), - image(VK_NULL_HANDLE), width(width), height(height), - format(format), - usageFlags(usageFlags), layout(VK_IMAGE_LAYOUT_UNDEFINED), + usageFlags(usageFlags), + image(VK_NULL_HANDLE), + format(format), mipLevels(mipLevels) { const VkImageCreateInfo imageCreateInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, @@ -34,7 +34,7 @@ namespace Vixen::Vk { .arrayLayers = 1, .samples = samples, .tiling = tiling, - .usage = usageFlags, + .usage = usageFlags | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, @@ -101,50 +101,38 @@ namespace Vixen::Vk { if (!bitmap) error("Failed to load image from file \"{}\"", path); - const auto& converted = FreeImage_ConvertTo32Bits(bitmap); - if (!converted) - error("Failed to convert image to 32 bits"); - - const auto& width = FreeImage_GetWidth(converted); - const auto& height = FreeImage_GetHeight(converted); - const auto& bitsPerPixel = FreeImage_GetBPP(converted); - const auto& pixels = FreeImage_GetBits(converted); - - const VkDeviceSize size = width * height * (bitsPerPixel / 8); - - auto staging = VkBuffer(device, Buffer::Usage::UNIFORM | Buffer::Usage::TRANSFER_SRC, size); - staging.write(reinterpret_cast(pixels), size, 0); + return from(device, bitmap); + } - FreeImage_Unload(converted); - FreeImage_Unload(bitmap); + VkImage VkImage::from(const std::shared_ptr& device, const std::string& format, const std::byte* data, + const uint32_t size) { + // TODO: Add some way to detect the format + const auto& memory = FreeImage_OpenMemory((BYTE*)data, size); + if (!memory) + error("Failed to open image from memory"); - FreeImage_DeInitialise(); + const auto& bitmap = FreeImage_LoadFromMemory(FreeImage_GetFIFFromFormat(format.c_str()), memory, 0); + if (!bitmap) + throw std::runtime_error("Failed to load image from memory"); - VkFormat f; - switch (bitsPerPixel) { - case 24: - f = VK_FORMAT_R8G8B8_SRGB; - break; - case 32: - f = VK_FORMAT_R8G8B8A8_SRGB; - break; - default: - throw std::runtime_error("Failed to determine format"); - } + return from(device, bitmap); + } + VkImage VkImage::from(const std::shared_ptr& device, const VkBuffer& buffer, const uint32_t width, + const uint32_t height, const VkFormat format) { auto image = VkImage( device, width, height, VK_SAMPLE_COUNT_1_BIT, - f, + format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, static_cast(std::floor(std::log2(std::max(width, height)))) + 1 ); image.transition(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - image.copyFrom(staging); + image.copyFrom(buffer); image.transition(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); return image; @@ -258,6 +246,42 @@ namespace Vixen::Vk { return mipLevels; } + VkImage VkImage::from(const std::shared_ptr& device, FIBITMAP* bitmap) { + const auto& converted = FreeImage_ConvertTo32Bits(bitmap); + if (!converted) + error("Failed to convert image to 32 bits"); + + const auto& width = FreeImage_GetWidth(converted); + const auto& height = FreeImage_GetHeight(converted); + const auto& bitsPerPixel = FreeImage_GetBPP(converted); + const auto& pixels = FreeImage_GetBits(converted); + + const VkDeviceSize size = width * height * (bitsPerPixel / 8); + + auto staging = VkBuffer(device, Buffer::Usage::UNIFORM | Buffer::Usage::TRANSFER_SRC, size); + staging.write(reinterpret_cast(pixels), size, 0); + + FreeImage_Unload(converted); + FreeImage_Unload(bitmap); + + FreeImage_DeInitialise(); + + VkFormat f; + // TODO: This will need a better implementation to detect the exact format later + switch (bitsPerPixel) { + case 24: + f = VK_FORMAT_B8G8R8_SRGB; + break; + case 32: + f = VK_FORMAT_B8G8R8A8_SRGB; + break; + default: + throw std::runtime_error("Failed to determine format"); + } + + return from(device, staging, width, height, f); + } + VkFormat VkImage::getFormat() const { return format; } diff --git a/src/engine/vk/VkImage.h b/src/engine/vk/VkImage.h index 47df8e5..5fd6e5f 100644 --- a/src/engine/vk/VkImage.h +++ b/src/engine/vk/VkImage.h @@ -48,6 +48,11 @@ namespace Vixen::Vk { static VkImage from(const std::shared_ptr& device, const std::string& path); + static VkImage from(const std::shared_ptr& device, const std::string& format, const std::byte* data, uint32_t size); + + static VkImage from(const std::shared_ptr& device, const VkBuffer& buffer, uint32_t width, + uint32_t height, VkFormat format); + void transition(VkImageLayout newLayout); void copyFrom(const VkBuffer& buffer); @@ -63,5 +68,8 @@ namespace Vixen::Vk { [[nodiscard]] const std::shared_ptr& getDevice() const; [[nodiscard]] uint8_t getMipLevels() const; + + private: + static VkImage from(const std::shared_ptr& device, FIBITMAP* bitmap); }; } diff --git a/src/engine/vk/test/main.cpp b/src/engine/vk/test/main.cpp index 2bf589a..07d7d0f 100644 --- a/src/engine/vk/test/main.cpp +++ b/src/engine/vk/test/main.cpp @@ -82,15 +82,19 @@ int main() { Assimp::Importer importer; const auto& scene = importer.ReadFile("../../src/engine/vk/test/vikingroom.glb", aiProcessPreset_TargetRealtime_Fast); - if (nullptr == scene) + if (!scene) throw std::runtime_error("Failed to load model from file"); const auto& mesh = scene->mMeshes[0]; + const auto& hasColors = mesh->HasVertexColors(0); + const auto& hasUvs = mesh->HasTextureCoords(0); + std::vector vertices(mesh->mNumVertices); for (uint32_t i = 0; i < mesh->mNumVertices; i++) { const auto& vertex = mesh->mVertices[i]; - const auto& color = mesh->HasVertexColors(i) ? *mesh->mColors[i] : aiColor4D{1.0f, 1.0f, 1.0f, 1.0f}; - const auto& uv = mesh->HasTextureCoords(i) ? *mesh->mTextureCoords[i] : aiVector3D{0.0f, 0.0f, 0.0f}; + // TODO: Instead of storing default values for each vertex where a color or UV is missing, we should compact this down to save memory + const auto& color = hasColors ? mesh->mColors[0][i] : aiColor4D{1.0f, 1.0f, 1.0f, 1.0f}; + const auto& uv = hasUvs ? mesh->mTextureCoords[0][i] : aiVector3D{1.0f, 1.0f, 1.0f}; vertices[i] = Vertex{ .position = {vertex.x, vertex.y, vertex.z}, @@ -101,7 +105,7 @@ int main() { std::vector indices(mesh->mNumFaces * 3); for (uint32_t i = 0; i < mesh->mNumFaces; i++) { - const auto &face = mesh->mFaces[i]; + const auto& face = mesh->mFaces[i]; if (face.mNumIndices != 3) { spdlog::warn("Skipping face with {} indices", face.mNumIndices); continue; @@ -112,6 +116,27 @@ int main() { indices[i * 3 + 2] = face.mIndices[2]; } + aiString path; + scene->mMaterials[mesh->mMaterialIndex]->GetTexture(aiTextureType_DIFFUSE, 0, &path); + + const auto& texture = scene->GetEmbeddedTexture(path.C_Str()); + assert(texture != nullptr && "Texture is nullptr"); + + std::shared_ptr image; + if (texture->mHeight != 0) { + image = nullptr; // TODO + } + else { + image = std::make_shared( + Vixen::Vk::VkImage::from( + vixen.device, + texture->achFormatHint, + reinterpret_cast(texture->pcData), + texture->mWidth + ) + ); + } + const auto buffer = Vixen::Vk::VkBuffer::stage( vixen.device, Vixen::Buffer::Usage::VERTEX | @@ -162,8 +187,8 @@ int main() { auto mvp = Vixen::Vk::VkDescriptorSet(vixen.device, descriptorPool, *program.getDescriptorSetLayout()); mvp.updateUniformBuffer(0, uniformBuffer, 0, uniformBuffer.getSize()); - auto image = std::make_shared( - Vixen::Vk::VkImage::from(vixen.device, "../../src/engine/vk/test/texture.jpg")); + auto testImage = std::make_shared( + Vixen::Vk::VkImage::from(vixen.device, std::string("../../src/engine/vk/test/texture.jpg"))); auto view = Vixen::Vk::VkImageView(image, VK_IMAGE_ASPECT_COLOR_BIT); auto sampler = Vixen::Vk::VkSampler(vixen.device); @@ -185,8 +210,8 @@ int main() { const double& now = glfwGetTime(); double deltaTime = now - lastFrame; lastFrame = now; - ubo.model = rotate(ubo.model, static_cast(deltaTime) * glm::radians(90.0f), - glm::vec3(0.0f, 0.0f, 1.0f)); + ubo.model = rotate(glm::mat4(1.0f), /*static_cast(deltaTime) **/ glm::radians(90.0f), + glm::vec3(1.0f, 0.0f, 0.0f)); ubo.view = camera.view(); ubo.projection = camera.perspective( static_cast(vixen.swapchain.getExtent().width) / diff --git a/src/engine/vk/test/vikingroom.glb b/src/engine/vk/test/vikingroom.glb index 8fd9de6..b784b1d 100644 Binary files a/src/engine/vk/test/vikingroom.glb and b/src/engine/vk/test/vikingroom.glb differ