82    if (gltfimage.uri.find_last_of(
".") != std::string::npos) {
 
   83        if (gltfimage.uri.substr(gltfimage.uri.find_last_of(
".") + 1) == 
"ktx") {
 
   93        unsigned char* buffer = 
nullptr;
 
   94        VkDeviceSize bufferSize = 0;
 
   95        bool deleteBuffer = 
false;
 
   96        if (gltfimage.component == 3) {
 
   99            bufferSize = gltfimage.width * gltfimage.height * 4;
 
  100            buffer = 
new unsigned char[bufferSize];
 
  101            unsigned char* rgba = buffer;
 
  102            unsigned char* rgb = &gltfimage.image[0];
 
  103            for (
size_t i = 0; i < gltfimage.width * gltfimage.height; ++i) {
 
  104                for (int32_t j = 0; j < 3; ++j) {
 
  113            buffer = &gltfimage.image[0];
 
  114            bufferSize = gltfimage.image.size();
 
  117        format = VK_FORMAT_R8G8B8A8_UNORM;
 
  119        VkFormatProperties formatProperties;
 
  121        width = gltfimage.width;
 
  122        height = gltfimage.height;
 
  125        vkGetPhysicalDeviceFormatProperties(
ctx->physicalDeviceHandle(), format, &formatProperties);
 
  126        assert(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT);
 
  127        assert(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT);
 
  129        VkMemoryAllocateInfo memAllocInfo{};
 
  130        memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
 
  131        VkMemoryRequirements memReqs{};
 
  133        VkBuffer stagingBuffer;
 
  134        VkDeviceMemory stagingMemory;
 
  136        VkBufferCreateInfo bufferCreateInfo{};
 
  137        bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
 
  138        bufferCreateInfo.size = bufferSize;
 
  139        bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
 
  140        bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
 
  141        VK_CHECK_RESULT(vkCreateBuffer(
ctx->deviceHandle(), &bufferCreateInfo, 
nullptr, &stagingBuffer));
 
  142        vkGetBufferMemoryRequirements(
ctx->deviceHandle(), stagingBuffer, &memReqs);
 
  143        memAllocInfo.allocationSize = memReqs.size;
 
  144        memAllocInfo.memoryTypeIndex = 
ctx->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
 
  145        VK_CHECK_RESULT(vkAllocateMemory(
ctx->deviceHandle(), &memAllocInfo, 
nullptr, &stagingMemory));
 
  146        VK_CHECK_RESULT(vkBindBufferMemory(
ctx->deviceHandle(), stagingBuffer, stagingMemory, 0));
 
  149        VK_CHECK_RESULT(vkMapMemory(
ctx->deviceHandle(), stagingMemory, 0, memReqs.size, 0, (
void**)&data));
 
  150        memcpy(data, buffer, bufferSize);
 
  151        vkUnmapMemory(
ctx->deviceHandle(), stagingMemory);
 
  153        VkImageCreateInfo imageCreateInfo{};
 
  154        imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
 
  155        imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
 
  156        imageCreateInfo.format = format;
 
  158        imageCreateInfo.arrayLayers = 1;
 
  159        imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
 
  160        imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
 
  161        imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
 
  162        imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
 
  163        imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 
  165        imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
 
  167        vkGetImageMemoryRequirements(
ctx->deviceHandle(), 
image, &memReqs);
 
  168        memAllocInfo.allocationSize = memReqs.size;
 
  169        memAllocInfo.memoryTypeIndex = 
ctx->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
 
  173        VkCommandBuffer copyCmd = 
ctx->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, 
true);
 
  175        VkImageSubresourceRange subresourceRange = {};
 
  176        subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
  177        subresourceRange.levelCount = 1;
 
  178        subresourceRange.layerCount = 1;
 
  181            VkImageMemoryBarrier imageMemoryBarrier{};
 
  182            imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
 
  183            imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 
  184            imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
 
  185            imageMemoryBarrier.srcAccessMask = 0;
 
  186            imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
 
  187            imageMemoryBarrier.image = 
image;
 
  188            imageMemoryBarrier.subresourceRange = subresourceRange;
 
  189            vkCmdPipelineBarrier(copyCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, 
nullptr, 0, 
nullptr, 1, &imageMemoryBarrier);
 
  192        VkBufferImageCopy bufferCopyRegion = {};
 
  193        bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
  194        bufferCopyRegion.imageSubresource.mipLevel = 0;
 
  195        bufferCopyRegion.imageSubresource.baseArrayLayer = 0;
 
  196        bufferCopyRegion.imageSubresource.layerCount = 1;
 
  197        bufferCopyRegion.imageExtent.width = 
width;
 
  198        bufferCopyRegion.imageExtent.height = 
height;
 
  199        bufferCopyRegion.imageExtent.depth = 1;
 
  201        vkCmdCopyBufferToImage(copyCmd, stagingBuffer, 
image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion);
 
  204            VkImageMemoryBarrier imageMemoryBarrier{};
 
  205            imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
 
  206            imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
 
  207            imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
 
  208            imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
 
  209            imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
 
  210            imageMemoryBarrier.image = 
image;
 
  211            imageMemoryBarrier.subresourceRange = subresourceRange;
 
  212            vkCmdPipelineBarrier(copyCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, 
nullptr, 0, 
nullptr, 1, &imageMemoryBarrier);
 
  215        ctx->flushCommandBuffer(copyCmd, 
ctx->graphicsQueueHandle(), 
true);
 
  217        vkFreeMemory(
ctx->deviceHandle(), stagingMemory, 
nullptr);
 
  218        vkDestroyBuffer(
ctx->deviceHandle(), stagingBuffer, 
nullptr);
 
  221        VkCommandBuffer blitCmd = 
ctx->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, 
true);
 
  222        for (uint32_t i = 1; i < 
mipLevels; i++) {
 
  223            VkImageBlit imageBlit{};
 
  225            imageBlit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
  226            imageBlit.srcSubresource.layerCount = 1;
 
  227            imageBlit.srcSubresource.mipLevel = i - 1;
 
  228            imageBlit.srcOffsets[1].x = int32_t(
width >> (i - 1));
 
  229            imageBlit.srcOffsets[1].y = int32_t(
height >> (i - 1));
 
  230            imageBlit.srcOffsets[1].z = 1;
 
  232            imageBlit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
  233            imageBlit.dstSubresource.layerCount = 1;
 
  234            imageBlit.dstSubresource.mipLevel = i;
 
  235            imageBlit.dstOffsets[1].x = int32_t(
width >> i);
 
  236            imageBlit.dstOffsets[1].y = int32_t(
height >> i);
 
  237            imageBlit.dstOffsets[1].z = 1;
 
  239            VkImageSubresourceRange mipSubRange = {};
 
  240            mipSubRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
  241            mipSubRange.baseMipLevel = i;
 
  242            mipSubRange.levelCount = 1;
 
  243            mipSubRange.layerCount = 1;
 
  246                VkImageMemoryBarrier imageMemoryBarrier{};
 
  247                imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
 
  248                imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 
  249                imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
 
  250                imageMemoryBarrier.srcAccessMask = 0;
 
  251                imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
 
  252                imageMemoryBarrier.image = 
image;
 
  253                imageMemoryBarrier.subresourceRange = mipSubRange;
 
  254                vkCmdPipelineBarrier(blitCmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, 
nullptr, 0, 
nullptr, 1, &imageMemoryBarrier);
 
  257            vkCmdBlitImage(blitCmd, 
image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 
image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &imageBlit, VK_FILTER_LINEAR);
 
  260                VkImageMemoryBarrier imageMemoryBarrier{};
 
  261                imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
 
  262                imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
 
  263                imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
 
  264                imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
 
  265                imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
 
  266                imageMemoryBarrier.image = 
image;
 
  267                imageMemoryBarrier.subresourceRange = mipSubRange;
 
  268                vkCmdPipelineBarrier(blitCmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, 
nullptr, 0, 
nullptr, 1, &imageMemoryBarrier);
 
  273        imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 
  276            VkImageMemoryBarrier imageMemoryBarrier{};
 
  277            imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
 
  278            imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
 
  279            imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 
  280            imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
 
  281            imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
 
  282            imageMemoryBarrier.image = 
image;
 
  283            imageMemoryBarrier.subresourceRange = subresourceRange;
 
  284            vkCmdPipelineBarrier(blitCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, 
nullptr, 0, 
nullptr, 1, &imageMemoryBarrier);
 
  287        ctx->flushCommandBuffer(blitCmd, 
ctx->graphicsQueueHandle(), 
true);
 
  291        std::string filename = path + 
"/" + gltfimage.uri;
 
  293        ktxTexture* ktxTexture;
 
  295        ktxResult result = KTX_SUCCESS;
 
  296#if defined(__ANDROID__) 
  297        AAsset* asset = AAssetManager_open(androidApp->activity->assetManager, filename.c_str(), AASSET_MODE_STREAMING);
 
  299            vks::tools::exitFatal(
"Could not load texture from " + filename + 
"\n\nThe file may be part of the additional asset pack.\n\nRun \"download_assets.py\" in the repository root to download the latest version.", -1);
 
  301        size_t size = AAsset_getLength(asset);
 
  303        ktx_uint8_t* textureData = 
new ktx_uint8_t[size];
 
  304        AAsset_read(asset, textureData, size);
 
  306        result = ktxTexture_CreateFromMemory(textureData, size, KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, &ktxTexture);
 
  307        delete[] textureData;
 
  310            vks::tools::exitFatal(
"Could not load texture from " + filename + 
"\n\nThe file may be part of the additional asset pack.\n\nRun \"download_assets.py\" in the repository root to download the latest version.", -1);
 
  312        result = ktxTexture_CreateFromNamedFile(filename.c_str(), KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, &ktxTexture);
 
  314        assert(result == KTX_SUCCESS);
 
  316        width = ktxTexture->baseWidth;
 
  317        height = ktxTexture->baseHeight;
 
  320        ktx_uint8_t* ktxTextureData = ktxTexture_GetData(ktxTexture);
 
  321        ktx_size_t ktxTextureSize = ktxTexture_GetSize(ktxTexture);
 
  323        format = VK_FORMAT_R8G8B8A8_UNORM;
 
  326        VkFormatProperties formatProperties;
 
  327        vkGetPhysicalDeviceFormatProperties(
ctx->physicalDeviceHandle(), format, &formatProperties);
 
  329        VkCommandBuffer copyCmd = 
ctx->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, 
true);
 
  330        VkBuffer stagingBuffer;
 
  331        VkDeviceMemory stagingMemory;
 
  334        bufferCreateInfo.size = ktxTextureSize;
 
  336        bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
 
  337        bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
 
  338        VK_CHECK_RESULT(vkCreateBuffer(
ctx->deviceHandle(), &bufferCreateInfo, 
nullptr, &stagingBuffer));
 
  341        VkMemoryRequirements memReqs;
 
  342        vkGetBufferMemoryRequirements(
ctx->deviceHandle(), stagingBuffer, &memReqs);
 
  343        memAllocInfo.allocationSize = memReqs.size;
 
  344        memAllocInfo.memoryTypeIndex = 
ctx->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
 
  345        VK_CHECK_RESULT(vkAllocateMemory(
ctx->deviceHandle(), &memAllocInfo, 
nullptr, &stagingMemory));
 
  346        VK_CHECK_RESULT(vkBindBufferMemory(
ctx->deviceHandle(), stagingBuffer, stagingMemory, 0));
 
  349        VK_CHECK_RESULT(vkMapMemory(
ctx->deviceHandle(), stagingMemory, 0, memReqs.size, 0, (
void**)&data));
 
  350        memcpy(data, ktxTextureData, ktxTextureSize);
 
  351        vkUnmapMemory(
ctx->deviceHandle(), stagingMemory);
 
  353        std::vector<VkBufferImageCopy> bufferCopyRegions;
 
  357            KTX_error_code result = ktxTexture_GetImageOffset(ktxTexture, i, 0, 0, &offset);
 
  358            assert(result == KTX_SUCCESS);
 
  359            VkBufferImageCopy bufferCopyRegion = {};
 
  360            bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
  361            bufferCopyRegion.imageSubresource.mipLevel = i;
 
  362            bufferCopyRegion.imageSubresource.baseArrayLayer = 0;
 
  363            bufferCopyRegion.imageSubresource.layerCount = 1;
 
  364            bufferCopyRegion.imageExtent.width = std::max(1u, ktxTexture->baseWidth >> i);
 
  365            bufferCopyRegion.imageExtent.height = std::max(1u, ktxTexture->baseHeight >> i);
 
  366            bufferCopyRegion.imageExtent.depth = 1;
 
  367            bufferCopyRegion.bufferOffset = offset;
 
  368            bufferCopyRegions.push_back(bufferCopyRegion);
 
  373        imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
 
  374        imageCreateInfo.format = format;
 
  376        imageCreateInfo.arrayLayers = 1;
 
  377        imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
 
  378        imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
 
  379        imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
 
  380        imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 
  382        imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
 
  385        vkGetImageMemoryRequirements(
ctx->deviceHandle(), 
image, &memReqs);
 
  386        memAllocInfo.allocationSize = memReqs.size;
 
  387        memAllocInfo.memoryTypeIndex = 
ctx->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
 
  391        VkImageSubresourceRange subresourceRange = {};
 
  392        subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
  393        subresourceRange.baseMipLevel = 0;
 
  395        subresourceRange.layerCount = 1;
 
  398        vkCmdCopyBufferToImage(copyCmd, stagingBuffer, 
image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 
static_cast<uint32_t
>(bufferCopyRegions.size()), bufferCopyRegions.data());
 
  400        ctx->flushCommandBuffer(copyCmd, 
ctx->graphicsQueueHandle());
 
  401        this->
imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 
  403        vkFreeMemory(
ctx->deviceHandle(), stagingMemory, 
nullptr);
 
  404        vkDestroyBuffer(
ctx->deviceHandle(), stagingBuffer, 
nullptr);
 
  406        ktxTexture_Destroy(ktxTexture);
 
  409    VkSamplerCreateInfo samplerInfo{};
 
  410    samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
 
  411    samplerInfo.magFilter = VK_FILTER_LINEAR;
 
  412    samplerInfo.minFilter = VK_FILTER_LINEAR;
 
  413    samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
 
  414    samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
 
  415    samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
 
  416    samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
 
  417    samplerInfo.compareOp = VK_COMPARE_OP_NEVER;
 
  418    samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
 
  419    samplerInfo.maxAnisotropy = 1.0;
 
  420    samplerInfo.anisotropyEnable = VK_FALSE;
 
  422    samplerInfo.maxAnisotropy = 8.0f;
 
  423    samplerInfo.anisotropyEnable = VK_TRUE;
 
  426    VkImageViewCreateInfo viewInfo{};
 
  427    viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
 
  428    viewInfo.image = 
image;
 
  429    viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
 
  430    viewInfo.format = format;
 
  431    viewInfo.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
 
  432    viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
  433    viewInfo.subresourceRange.layerCount = 1;
 
  434    viewInfo.subresourceRange.levelCount = 
mipLevels;
 
 
  642    unsigned char* buffer = 
new unsigned char[bufferSize];
 
  643    memset(buffer, 0, bufferSize);
 
  645    VkBuffer stagingBuffer;
 
  646    VkDeviceMemory stagingMemory;
 
  648    bufferCreateInfo.size = bufferSize;
 
  650    bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
 
  651    bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
 
  652    VK_CHECK_RESULT(vkCreateBuffer(
ctx->deviceHandle(), &bufferCreateInfo, 
nullptr, &stagingBuffer));
 
  655    VkMemoryRequirements memReqs;
 
  656    vkGetBufferMemoryRequirements(
ctx->deviceHandle(), stagingBuffer, &memReqs);
 
  657    memAllocInfo.allocationSize = memReqs.size;
 
  658    memAllocInfo.memoryTypeIndex = 
ctx->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
 
  659    VK_CHECK_RESULT(vkAllocateMemory(
ctx->deviceHandle(), &memAllocInfo, 
nullptr, &stagingMemory));
 
  660    VK_CHECK_RESULT(vkBindBufferMemory(
ctx->deviceHandle(), stagingBuffer, stagingMemory, 0));
 
  664    VK_CHECK_RESULT(vkMapMemory(
ctx->deviceHandle(), stagingMemory, 0, memReqs.size, 0, (
void**)&data));
 
  665    memcpy(data, buffer, bufferSize);
 
  666    vkUnmapMemory(
ctx->deviceHandle(), stagingMemory);
 
  668    VkBufferImageCopy bufferCopyRegion = {};
 
  669    bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
  670    bufferCopyRegion.imageSubresource.layerCount = 1;
 
  671    bufferCopyRegion.imageExtent.width = 
emptyTexture.width;
 
  672    bufferCopyRegion.imageExtent.height = 
emptyTexture.height;
 
  673    bufferCopyRegion.imageExtent.depth = 1;
 
  677    imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
 
  678    imageCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
 
  679    imageCreateInfo.mipLevels = 1;
 
  680    imageCreateInfo.arrayLayers = 1;
 
  681    imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
 
  682    imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
 
  683    imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
 
  684    imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 
  686    imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
 
  689    vkGetImageMemoryRequirements(
ctx->deviceHandle(), 
emptyTexture.image, &memReqs);
 
  690    memAllocInfo.allocationSize = memReqs.size;
 
  691    memAllocInfo.memoryTypeIndex = 
ctx->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
 
  695    VkImageSubresourceRange subresourceRange{};
 
  696    subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
  697    subresourceRange.baseMipLevel = 0;
 
  698    subresourceRange.levelCount = 1;
 
  699    subresourceRange.layerCount = 1;
 
  701    VkCommandBuffer copyCmd = 
ctx->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, 
true);
 
  703    vkCmdCopyBufferToImage(copyCmd, stagingBuffer, 
emptyTexture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion);
 
  705    ctx->flushCommandBuffer(copyCmd, 
ctx->graphicsQueueHandle());
 
  706    emptyTexture.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 
  709    vkFreeMemory(
ctx->deviceHandle(), stagingMemory, 
nullptr);
 
  710    vkDestroyBuffer(
ctx->deviceHandle(), stagingBuffer, 
nullptr);
 
  713    samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
 
  714    samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
 
  715    samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
 
  716    samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
 
  717    samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
 
  718    samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
 
  719    samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER;
 
  720    samplerCreateInfo.maxAnisotropy = 1.0f;
 
  724    viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
 
  725    viewCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
 
  726    viewCreateInfo.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
 
  727    viewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
 
  728    viewCreateInfo.subresourceRange.levelCount = 1;
 
  732    emptyTexture.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 
 
  774void vkglTF::Model::loadNode(
vkglTF::Node *parent, 
const tinygltf::Node &node, uint32_t nodeIndex, 
const tinygltf::Model &model, std::vector<uint32_t>& indexBuffer, std::vector<Vertex>& vertexBuffer, 
float globalscale)
 
  777    newNode->
index = nodeIndex;
 
  779    newNode->
name = node.name;
 
  781    newNode->
matrix = glm::mat4(1.0f);
 
  784    glm::vec3 translation = glm::vec3(0.0f);
 
  785    if (node.translation.size() == 3) {
 
  786        translation = glm::make_vec3(node.translation.data());
 
  789    glm::mat4 rotation = glm::mat4(1.0f);
 
  790    if (node.rotation.size() == 4) {
 
  791        glm::quat q = glm::make_quat(node.rotation.data());
 
  794    glm::vec3 scale = glm::vec3(1.0f);
 
  795    if (node.scale.size() == 3) {
 
  796        scale = glm::make_vec3(node.scale.data());
 
  797        newNode->
scale = scale;
 
  799    if (node.matrix.size() == 16) {
 
  800        newNode->
matrix = glm::make_mat4x4(node.matrix.data());
 
  801        if (globalscale != 1.0f) {
 
  807    if (node.children.size() > 0) {
 
  808        for (
auto i = 0; i < node.children.size(); i++) {
 
  809            loadNode(newNode, model.nodes[node.children[i]], node.
children[i], model, indexBuffer, vertexBuffer, globalscale);
 
  814    if (node.mesh > -1) {
 
  815        const tinygltf::Mesh mesh = model.meshes[node.mesh];
 
  817        newMesh->
name = mesh.name;
 
  818        for (
size_t j = 0; j < mesh.primitives.size(); j++) {
 
  819            const tinygltf::Primitive &primitive = mesh.primitives[j];
 
  820            if (primitive.indices < 0) {
 
  823            uint32_t indexStart = 
static_cast<uint32_t
>(indexBuffer.size());
 
  824            uint32_t vertexStart = 
static_cast<uint32_t
>(vertexBuffer.size());
 
  825            uint32_t indexCount = 0;
 
  826            uint32_t vertexCount = 0;
 
  829            bool hasSkin = 
false;
 
  832                const float *bufferPos = 
nullptr;
 
  833                const float *bufferNormals = 
nullptr;
 
  834                const float *bufferTexCoords = 
nullptr;
 
  835                const float* bufferColors = 
nullptr;
 
  836                const float *bufferTangents = 
nullptr;
 
  837                uint32_t numColorComponents;
 
  838                const uint16_t *bufferJoints = 
nullptr;
 
  839                const float *bufferWeights = 
nullptr;
 
  842                assert(primitive.attributes.find(
"POSITION") != primitive.attributes.end());
 
  844                const tinygltf::Accessor &posAccessor = model.accessors[primitive.attributes.find(
"POSITION")->second];
 
  845                const tinygltf::BufferView &posView = model.bufferViews[posAccessor.bufferView];
 
  846                bufferPos = 
reinterpret_cast<const float *
>(&(model.buffers[posView.buffer].data[posAccessor.byteOffset + posView.byteOffset]));
 
  847                posMin = glm::vec3(posAccessor.minValues[0], posAccessor.minValues[1], posAccessor.minValues[2]);
 
  848                posMax = glm::vec3(posAccessor.maxValues[0], posAccessor.maxValues[1], posAccessor.maxValues[2]);
 
  850                if (primitive.attributes.find(
"NORMAL") != primitive.attributes.end()) {
 
  851                    const tinygltf::Accessor &normAccessor = model.accessors[primitive.attributes.find(
"NORMAL")->second];
 
  852                    const tinygltf::BufferView &normView = model.bufferViews[normAccessor.bufferView];
 
  853                    bufferNormals = 
reinterpret_cast<const float *
>(&(model.buffers[normView.buffer].data[normAccessor.byteOffset + normView.byteOffset]));
 
  856                if (primitive.attributes.find(
"TEXCOORD_0") != primitive.attributes.end()) {
 
  857                    const tinygltf::Accessor &uvAccessor = model.accessors[primitive.attributes.find(
"TEXCOORD_0")->second];
 
  858                    const tinygltf::BufferView &uvView = model.bufferViews[uvAccessor.bufferView];
 
  859                    bufferTexCoords = 
reinterpret_cast<const float *
>(&(model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset]));
 
  862                if (primitive.attributes.find(
"COLOR_0") != primitive.attributes.end())
 
  864                    const tinygltf::Accessor& colorAccessor = model.accessors[primitive.attributes.find(
"COLOR_0")->second];
 
  865                    const tinygltf::BufferView& colorView = model.bufferViews[colorAccessor.bufferView];
 
  867                    numColorComponents = colorAccessor.type == TINYGLTF_PARAMETER_TYPE_FLOAT_VEC3 ? 3 : 4;
 
  868                    bufferColors = 
reinterpret_cast<const float*
>(&(model.buffers[colorView.buffer].data[colorAccessor.byteOffset + colorView.byteOffset]));
 
  871                if (primitive.attributes.find(
"TANGENT") != primitive.attributes.end())
 
  873                    const tinygltf::Accessor &tangentAccessor = model.accessors[primitive.attributes.find(
"TANGENT")->second];
 
  874                    const tinygltf::BufferView &tangentView = model.bufferViews[tangentAccessor.bufferView];
 
  875                    bufferTangents = 
reinterpret_cast<const float *
>(&(model.buffers[tangentView.buffer].data[tangentAccessor.byteOffset + tangentView.byteOffset]));
 
  880                if (primitive.attributes.find(
"JOINTS_0") != primitive.attributes.end()) {
 
  881                    const tinygltf::Accessor &jointAccessor = model.accessors[primitive.attributes.find(
"JOINTS_0")->second];
 
  882                    const tinygltf::BufferView &jointView = model.bufferViews[jointAccessor.bufferView];
 
  883                    bufferJoints = 
reinterpret_cast<const uint16_t *
>(&(model.buffers[jointView.buffer].data[jointAccessor.byteOffset + jointView.byteOffset]));
 
  886                if (primitive.attributes.find(
"WEIGHTS_0") != primitive.attributes.end()) {
 
  887                    const tinygltf::Accessor &uvAccessor = model.accessors[primitive.attributes.find(
"WEIGHTS_0")->second];
 
  888                    const tinygltf::BufferView &uvView = model.bufferViews[uvAccessor.bufferView];
 
  889                    bufferWeights = 
reinterpret_cast<const float *
>(&(model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset]));
 
  892                hasSkin = (bufferJoints && bufferWeights);
 
  894                vertexCount = 
static_cast<uint32_t
>(posAccessor.count);
 
  896                for (
size_t v = 0; v < posAccessor.count; v++) {
 
  898                    vert.
pos = glm::make_vec3(&bufferPos[v * 3]);
 
  899                    vert.normal = glm::normalize(glm::vec3(bufferNormals ? glm::make_vec3(&bufferNormals[v * 3]) : glm::vec3(0.0f)));
 
  900                    vert.uv = bufferTexCoords ? glm::make_vec2(&bufferTexCoords[v * 2]) : glm::vec2(0.0f);
 
  902                        switch (numColorComponents) {
 
  904                                vert.color = glm::vec4(glm::make_vec3(&bufferColors[v * 3]), 1.0f);
 
  906                                vert.color = glm::make_vec4(&bufferColors[v * 4]);
 
  910                        vert.color = glm::vec4(1.0f);
 
  912                    vert.tangent = bufferTangents ? glm::vec4(glm::make_vec4(&bufferTangents[v * 4])) : glm::vec4(0.0f);
 
  913                    vert.joint0 = hasSkin ? glm::vec4(glm::make_vec4(&bufferJoints[v * 4])) : glm::vec4(0.0f);
 
  914                    vert.weight0 = hasSkin ? glm::make_vec4(&bufferWeights[v * 4]) : glm::vec4(0.0f);
 
  915                    vertexBuffer.push_back(vert);
 
  920                const tinygltf::Accessor &accessor = model.accessors[primitive.indices];
 
  921                const tinygltf::BufferView &bufferView = model.bufferViews[accessor.bufferView];
 
  922                const tinygltf::Buffer &buffer = model.buffers[bufferView.buffer];
 
  924                indexCount = 
static_cast<uint32_t
>(accessor.count);
 
  926                switch (accessor.componentType) {
 
  927                case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT: {
 
  928                    uint32_t *buf = 
new uint32_t[accessor.count];
 
  929                    memcpy(buf, &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * 
sizeof(uint32_t));
 
  930                    for (
size_t index = 0; index < accessor.count; index++) {
 
  931                        indexBuffer.push_back(buf[index] + vertexStart);
 
  935                case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT: {
 
  936                    uint16_t *buf = 
new uint16_t[accessor.count];
 
  937                    memcpy(buf, &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * 
sizeof(uint16_t));
 
  938                    for (
size_t index = 0; index < accessor.count; index++) {
 
  939                        indexBuffer.push_back(buf[index] + vertexStart);
 
  943                case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE: {
 
  944                    uint8_t *buf = 
new uint8_t[accessor.count];
 
  945                    memcpy(buf, &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * 
sizeof(uint8_t));
 
  946                    for (
size_t index = 0; index < accessor.count; index++) {
 
  947                        indexBuffer.push_back(buf[index] + vertexStart);
 
  952                    std::cerr << 
"Index component type " << accessor.componentType << 
" not supported!" << std::endl;
 
  962        newNode->
mesh = newMesh;
 
  965        parent->
children.push_back(newNode);
 
  967        nodes.push_back(newNode);
 
 
 1179    tinygltf::Model gltfModel;
 
 1180    tinygltf::TinyGLTF gltfContext;
 
 1186#if defined(__ANDROID__) 
 1189    tinygltf::asset_manager = androidApp->activity->assetManager;
 
 1191    size_t pos = filename.find_last_of(
'/');
 
 1192    path = filename.substr(0, pos);
 
 1194    std::string error, warning;
 
 1196#if defined(__ANDROID__) 
 1199    tinygltf::asset_manager = androidApp->activity->assetManager;
 
 1201    bool fileLoaded = gltfContext.LoadASCIIFromFile(&gltfModel, &error, &warning, filename);
 
 1203    std::vector<uint32_t> indexBuffer;
 
 1204    std::vector<Vertex> vertexBuffer;
 
 1211        const tinygltf::Scene &scene = gltfModel.scenes[gltfModel.defaultScene > -1 ? gltfModel.defaultScene : 0];
 
 1212        for (
size_t i = 0; i < scene.nodes.size(); i++) {
 
 1213            const tinygltf::Node node = gltfModel.nodes[scene.nodes[i]];
 
 1214            loadNode(
nullptr, node, scene.nodes[i], gltfModel, indexBuffer, vertexBuffer, scale);
 
 1216        if (gltfModel.animations.size() > 0) {
 
 1223            if (node->skinIndex > -1) {
 
 1224                node->skin = 
skins[node->skinIndex];
 
 1245                const glm::mat4 localMatrix = node->getMatrix();
 
 1246                for (
Primitive* primitive : node->mesh->primitives) {
 
 1247                    for (uint32_t i = 0; i < primitive->
vertexCount; i++) {
 
 1251                            vertex.
pos = glm::vec3(localMatrix * glm::vec4(vertex.
pos, 1.0f));
 
 1252                            vertex.
normal = glm::normalize(glm::mat3(localMatrix) * vertex.
normal);
 
 1256                            vertex.
pos.y *= -1.0f;
 
 1257                            vertex.
normal.y *= -1.0f;
 
 1260                        if (preMultiplyColor) {
 
 1269    for (
auto extension : gltfModel.extensionsUsed) {
 
 1270        if (extension == 
"KHR_materials_pbrSpecularGlossiness") {
 
 1271            std::cout << 
"Required extension: " << extension;
 
 1276    size_t vertexBufferSize = vertexBuffer.size() * 
sizeof(
Vertex);
 
 1277    size_t indexBufferSize = indexBuffer.size() * 
sizeof(uint32_t);
 
 1278    indices.count = 
static_cast<uint32_t
>(indexBuffer.size());
 
 1279    vertices.count = 
static_cast<uint32_t
>(vertexBuffer.size());
 
 1281    assert((vertexBufferSize > 0) && (indexBufferSize > 0));
 
 1283    struct StagingBuffer {
 
 1285        VkDeviceMemory memory;
 
 1286    } vertexStaging, indexStaging;
 
 1291        VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
 
 1292        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
 
 1294        &vertexStaging.buffer,
 
 1295        &vertexStaging.memory,
 
 1296        vertexBuffer.data()));
 
 1299        VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
 
 1300        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
 
 1302        &indexStaging.buffer,
 
 1303        &indexStaging.memory,
 
 1304        indexBuffer.data()));
 
 1309        VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | 
memoryPropertyFlags,
 
 1310        VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
 
 1316        VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | 
memoryPropertyFlags,
 
 1317        VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
 
 1323    VkCommandBuffer copyCmd = 
ctx->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, 
true);
 
 1325    VkBufferCopy copyRegion = {};
 
 1327    copyRegion.size = vertexBufferSize;
 
 1328    vkCmdCopyBuffer(copyCmd, vertexStaging.buffer, 
vertices.buffer, 1, ©Region);
 
 1330    copyRegion.size = indexBufferSize;
 
 1331    vkCmdCopyBuffer(copyCmd, indexStaging.buffer, 
indices.buffer, 1, ©Region);
 
 1333    ctx->flushCommandBuffer(copyCmd, 
ctx->graphicsQueueHandle(), 
true);
 
 1335    vkDestroyBuffer(
ctx->deviceHandle(), vertexStaging.buffer, 
nullptr);
 
 1336    vkFreeMemory(
ctx->deviceHandle(), vertexStaging.memory, 
nullptr);
 
 1337    vkDestroyBuffer(
ctx->deviceHandle(), indexStaging.buffer, 
nullptr);
 
 1338    vkFreeMemory(
ctx->deviceHandle(), indexStaging.memory, 
nullptr);
 
 1343    uint32_t uboCount{ 0 };
 
 1344    uint32_t imageCount{ 0 };
 
 1351        if (material.baseColorTexture != 
nullptr) {
 
 1355    std::vector<VkDescriptorPoolSize> poolSizes = {
 
 1356        { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uboCount },
 
 1358    if (imageCount > 0) {
 
 1360            poolSizes.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, imageCount });
 
 1363            poolSizes.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, imageCount });
 
 1366    VkDescriptorPoolCreateInfo descriptorPoolCI{};
 
 1367    descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
 
 1368    descriptorPoolCI.poolSizeCount = 
static_cast<uint32_t
>(poolSizes.size());
 
 1369    descriptorPoolCI.pPoolSizes = poolSizes.data();
 
 1370    descriptorPoolCI.maxSets = uboCount + imageCount;
 
 1377            std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = {
 
 1380            VkDescriptorSetLayoutCreateInfo descriptorLayoutCI{};
 
 1381            descriptorLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
 
 1382            descriptorLayoutCI.bindingCount = 
static_cast<uint32_t
>(setLayoutBindings.size());
 
 1383            descriptorLayoutCI.pBindings = setLayoutBindings.data();
 
 1386        for (
auto node : 
nodes) {
 
 1395            std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings{};
 
 1402            VkDescriptorSetLayoutCreateInfo descriptorLayoutCI{};
 
 1403            descriptorLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
 
 1404            descriptorLayoutCI.bindingCount = 
static_cast<uint32_t
>(setLayoutBindings.size());
 
 1405            descriptorLayoutCI.pBindings = setLayoutBindings.data();
 
 1409            if (material.baseColorTexture != 
nullptr) {