/**
         * Load a 2D texture including all mip levels
         *
         * @param filename File to load (supports .ktx and .dds)
         * @param format Vulkan format of the image data stored in the file
         * @param device Vulkan device to create the texture on
         * @param copyQueue Queue used for the texture staging copy commands (must support transfer)
         * @param (Optional) imageUsageFlags Usage flags for the texture's image (defaults to VK_IMAGE_USAGE_SAMPLED_BIT)
         * @param (Optional) imageLayout Usage layout for the texture (defaults VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
         * @param (Optional) forceLinear Force linear tiling (not advised, defaults to false)
         *
         */
        public void FromTextureAsset(
            TextureAsset asset,
            GraphicsDevice device,
            VkImageUsageFlags imageUsageFlags = VkImageUsageFlags.Sampled,
            VkImageLayout imageLayout         = VkImageLayout.ShaderReadOnlyOptimal)
        {
            VkFormat format = VkFormat.Undefined;

            KtxFile tex2D = asset.GetTexture();

            format = GlFormatToVulkanFormat.vkGetFormatFromOpenGLInternalFormat(tex2D.Header.GlInternalFormat, tex2D.Header.GlFormat, tex2D.Header.GlType);

            width  = tex2D.Header.PixelWidth;
            height = tex2D.Header.PixelHeight;
            if (height == 0)
            {
                height = width;
            }
            mipLevels = tex2D.Header.NumberOfMipmapLevels;

            this.imageLayout = imageLayout;
            this.format      = format;
            this.device      = device;

            // Get device properites for the requested texture format
            VkFormatProperties formatProperties;

            vkGetPhysicalDeviceFormatProperties(device.physicalDevice, format, out formatProperties);

            VkMemoryAllocateInfo memAllocInfo = Initializers.memoryAllocateInfo();
            VkMemoryRequirements memReqs;

            // Create optimal tiled target image
            VkImageCreateInfo imageCreateInfo = Initializers.imageCreateInfo();

            imageCreateInfo.imageType     = VkImageType.Image2D;
            imageCreateInfo.format        = format;
            imageCreateInfo.mipLevels     = mipLevels;
            imageCreateInfo.arrayLayers   = 1;
            imageCreateInfo.samples       = VkSampleCountFlags.Count1;
            imageCreateInfo.tiling        = VkImageTiling.Optimal;
            imageCreateInfo.sharingMode   = VkSharingMode.Exclusive;
            imageCreateInfo.initialLayout = VkImageLayout.Undefined;
            imageCreateInfo.extent        = new VkExtent3D {
                width = width, height = height, depth = 1
            };
            imageCreateInfo.usage = imageUsageFlags;
            // Ensure that the TRANSFER_DST bit is set for staging
            if ((imageCreateInfo.usage & VkImageUsageFlags.TransferDst) == 0)
            {
                imageCreateInfo.usage |= VkImageUsageFlags.TransferDst;
            }
            Util.CheckResult(vkCreateImage(device.device, &imageCreateInfo, null, out image));

            vkGetImageMemoryRequirements(device.device, image, &memReqs);

            memAllocInfo.allocationSize = memReqs.size;

            memory = device.memoryAllocator.Allocate(memReqs.size, memReqs.alignment, memReqs.memoryTypeBits, false);
            Util.CheckResult(vkBindImageMemory(device.device, image, memory.vkDeviceMemory, memory.offset));

            //memAllocInfo.memoryTypeIndex = device.vulkanDevice.getMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal);
            //Util.CheckResult(vkAllocateMemory(device.device, &memAllocInfo, null, out deviceMemory));
            //Util.CheckResult(vkBindImageMemory(device.device, image, deviceMemory, 0));

            TransferDataKtx(tex2D);

            CreateSampler();

            CreateView();

            // Update descriptor image info member that can be used for setting up descriptor sets
            UpdateDescriptor();
        }