#include "entities.hpp" DynArray globalEntityTypes{16}; VkDescriptorSetLayout vkDescriptorSetLayout_Texture = VK_NULL_HANDLE; VkPipelineLayout vkPipelineLayout_Texture = VK_NULL_HANDLE; VkSampler vkSampler_Texture = VK_NULL_HANDLE; struct ImplementedPipelines { union { VkPipeline pipelines[2] = { VK_NULL_HANDLE, VK_NULL_HANDLE }; struct { VkPipeline Texture; VkPipeline TextureWireframe; }; }; } vkPipelines; VkPipelineLayoutCreateInfo sharedVkPipelineLayoutCreateInfo { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .pNext = nullptr, .flags = 0, .setLayoutCount = 0, .pSetLayouts = nullptr, .pushConstantRangeCount = 0, .pPushConstantRanges = nullptr, }; VkWriteDescriptorSet uboDescriptor { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = nullptr, .dstSet = nullptr, .dstBinding = 0, .dstArrayElement = 0, .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .pImageInfo = nullptr, .pBufferInfo = nullptr, .pTexelBufferView = nullptr, }; VkDescriptorImageInfo textureDescriptorInfo { .sampler = nullptr, .imageView = nullptr, .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, }; VkWriteDescriptorSet samplerDescriptor { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = nullptr, .dstSet = nullptr, .dstBinding = 1, .dstArrayElement = 0, .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .pImageInfo = &textureDescriptorInfo, .pBufferInfo = nullptr, .pTexelBufferView = nullptr, }; void EntityType_Init() { globalEntityTypes.Push( EntityType { .modelsDir = "assets/models", .modelFile = "cube.gltf", .entityTypeCode = "EntTypeCube", .entityHandle = ECS_CreateEntity(), .startingInstanceCount = 16, .Importer_GLTF = { .AccessorIndexVertex = 0, .AccessorIndexNormal = 1, .AccessorIndexUV = 2, .AccessorIndexIndex = 3, } } ); globalEntityTypes.Push( EntityType { .modelsDir = "assets/models", .modelFile = "plane.gltf", .entityTypeCode = "EntTypePlane", .entityHandle = ECS_CreateEntity(), .startingInstanceCount = 16, .Importer_GLTF = { .AccessorIndexVertex = 0, .AccessorIndexNormal = 1, .AccessorIndexUV = 2, .AccessorIndexIndex = 3, } } ); VkDescriptorSetLayoutBinding vkDescriptorSetLayoutBindings[2]; for (long i = 0; i < 2; ++i) { vkDescriptorSetLayoutBindings[i].pImmutableSamplers = nullptr; } vkDescriptorSetLayoutBindings[0].binding = 0; vkDescriptorSetLayoutBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; vkDescriptorSetLayoutBindings[0].descriptorCount = 1; vkDescriptorSetLayoutBindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; vkDescriptorSetLayoutBindings[1].binding = 1; vkDescriptorSetLayoutBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; vkDescriptorSetLayoutBindings[1].descriptorCount = 1; vkDescriptorSetLayoutBindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; VkDescriptorSetLayoutCreateInfo vkDescriptorSetLayoutCreateInfo { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, .pNext = nullptr, .flags = 0, .bindingCount = 2, .pBindings = vkDescriptorSetLayoutBindings, }; vkCreateDescriptorSetLayout(vkDevice, &vkDescriptorSetLayoutCreateInfo, vkAllocator, &vkDescriptorSetLayout_Texture); VkPipelineLayoutCreateInfo vkPipelineLayoutCreateInfo { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .pNext = nullptr, .flags = 0, .setLayoutCount = 1, .pSetLayouts = &vkDescriptorSetLayout_Texture, .pushConstantRangeCount = 0, .pPushConstantRanges = nullptr, }; vkCreatePipelineLayout(vkDevice, &vkPipelineLayoutCreateInfo, vkAllocator, &vkPipelineLayout_Texture); VkSamplerCreateInfo vkSamplerCreateInfo; vkSamplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; vkSamplerCreateInfo.pNext = nullptr; vkSamplerCreateInfo.flags = 0; vkSamplerCreateInfo.magFilter = VK_FILTER_NEAREST; vkSamplerCreateInfo.minFilter = VK_FILTER_NEAREST; vkSamplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; vkSamplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; vkSamplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; vkSamplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; vkSamplerCreateInfo.mipLodBias = 0.0f; vkSamplerCreateInfo.anisotropyEnable = VK_TRUE; vkSamplerCreateInfo.maxAnisotropy = vkPhysicalDeviceProperties.limits.maxSamplerAnisotropy; vkSamplerCreateInfo.compareEnable = VK_FALSE; vkSamplerCreateInfo.compareOp = VK_COMPARE_OP_ALWAYS; vkSamplerCreateInfo.minLod = 0.0f; // TODO MipMap vkSamplerCreateInfo.maxLod = 1; vkSamplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; vkSamplerCreateInfo.unnormalizedCoordinates = VK_FALSE; vkCreateSampler(vkDevice, &vkSamplerCreateInfo, vkAllocator, &vkSampler_Texture); // pipelines { const long vertexBindingCount = 4; long index = 0; VkVertexInputBindingDescription vertInputBD[vertexBindingCount]; for (long i = 0; i < vertexBindingCount; ++i) { vertInputBD[i].binding = i; } // model vertex vertInputBD[index].stride = sizeof(glm::vec3); vertInputBD[index].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; index += 1; // model normals vertInputBD[index].stride = sizeof(glm::vec3); vertInputBD[index].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; index += 1; // model UV vertInputBD[index].stride = sizeof(glm::vec2); vertInputBD[index].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; index += 1; // model index // vertInputBD[index].stride = sizeof(uint16_t); // vertInputBD[index++].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; // index += 1; // instance vertInputBD[index].stride = sizeof(glm::vec3) * 3; vertInputBD[index].inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; const long vertexAttrDescCount = 6; long runningOffset = 0; index = 0; VkVertexInputAttributeDescription vertAttrDesc[vertexAttrDescCount]; for (long i = 0; i < vertexAttrDescCount; ++i) { vertAttrDesc[i].location = i; } // model vertex vertAttrDesc[index].binding = 0; vertAttrDesc[index].format = VK_FORMAT_R32G32B32_SFLOAT; vertAttrDesc[index].offset = runningOffset; runningOffset += sizeof(glm::vec3); index += 1; // model normals vertAttrDesc[index].binding = 1; vertAttrDesc[index].format = VK_FORMAT_R32G32B32_SFLOAT; vertAttrDesc[index].offset = runningOffset; runningOffset += sizeof(glm::vec3); index += 1; // model UV vertAttrDesc[index].binding = 2; vertAttrDesc[index].format = VK_FORMAT_R32G32_SFLOAT; vertAttrDesc[index].offset = runningOffset; runningOffset += sizeof(glm::vec2); index += 1; // instance pos vertAttrDesc[index].binding = 3; vertAttrDesc[index].format = VK_FORMAT_R32G32B32_SFLOAT; vertAttrDesc[index].offset = runningOffset; runningOffset += sizeof(glm::vec3); index += 1; // instance rot vertAttrDesc[index].binding = 3; vertAttrDesc[index].format = VK_FORMAT_R32G32B32_SFLOAT; vertAttrDesc[index].offset = runningOffset; runningOffset += sizeof(glm::vec3); index += 1; // instance scale vertAttrDesc[index].binding = 3; vertAttrDesc[index].format = VK_FORMAT_R32G32B32_SFLOAT; vertAttrDesc[index].offset = runningOffset; // runningOffset += sizeof(glm::vec3); // index += 1; // instance texture index // vertAttrDesc[index].binding = 3; // vertAttrDesc[index].format = VK_FORMAT_R32_SFLOAT; // vertAttrDesc[index].offset = runningOffset; // runningOffset += sizeof(float); // index += 1; VkPipelineVertexInputStateCreateInfo vkPipelineVertexInputStateCreateInfo; vkPipelineVertexInputStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vkPipelineVertexInputStateCreateInfo.pNext = nullptr; vkPipelineVertexInputStateCreateInfo.flags = {}; vkPipelineVertexInputStateCreateInfo.vertexBindingDescriptionCount = vertexBindingCount; vkPipelineVertexInputStateCreateInfo.pVertexBindingDescriptions = vertInputBD; vkPipelineVertexInputStateCreateInfo.vertexAttributeDescriptionCount = vertexAttrDescCount; vkPipelineVertexInputStateCreateInfo.pVertexAttributeDescriptions = vertAttrDesc; VkPipelineInputAssemblyStateCreateInfo vkPipelineInputAssemblyStateCreateInfo; vkPipelineInputAssemblyStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; vkPipelineInputAssemblyStateCreateInfo.pNext = nullptr; vkPipelineInputAssemblyStateCreateInfo.flags = {}; vkPipelineInputAssemblyStateCreateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; vkPipelineInputAssemblyStateCreateInfo.primitiveRestartEnable = VK_FALSE; // TODO - is this right? set to dynamic later VkPipelineViewportStateCreateInfo vkPipelineViewportStateCreateInfo; vkPipelineViewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; vkPipelineViewportStateCreateInfo.pNext = nullptr; vkPipelineViewportStateCreateInfo.flags = {}; vkPipelineViewportStateCreateInfo.viewportCount = 1; vkPipelineViewportStateCreateInfo.pViewports = nullptr; vkPipelineViewportStateCreateInfo.scissorCount = 1; vkPipelineViewportStateCreateInfo.pScissors = nullptr; VkPipelineRasterizationStateCreateInfo vkPipelineRasterizationStateCreateInfoFill; vkPipelineRasterizationStateCreateInfoFill.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; vkPipelineRasterizationStateCreateInfoFill.pNext = nullptr; vkPipelineRasterizationStateCreateInfoFill.flags = {}; vkPipelineRasterizationStateCreateInfoFill.depthClampEnable = VK_FALSE; vkPipelineRasterizationStateCreateInfoFill.rasterizerDiscardEnable = VK_FALSE; vkPipelineRasterizationStateCreateInfoFill.polygonMode = VK_POLYGON_MODE_FILL; vkPipelineRasterizationStateCreateInfoFill.cullMode = VK_CULL_MODE_BACK_BIT; vkPipelineRasterizationStateCreateInfoFill.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; vkPipelineRasterizationStateCreateInfoFill.depthBiasEnable = VK_FALSE; vkPipelineRasterizationStateCreateInfoFill.depthBiasConstantFactor = 0.0f; vkPipelineRasterizationStateCreateInfoFill.depthBiasClamp = 0.0f; vkPipelineRasterizationStateCreateInfoFill.depthBiasSlopeFactor = 0.0f; vkPipelineRasterizationStateCreateInfoFill.lineWidth = 1.0f; VkPipelineRasterizationStateCreateInfo vkPipelineRasterizationStateCreateInfoLine{vkPipelineRasterizationStateCreateInfoFill}; vkPipelineRasterizationStateCreateInfoLine.polygonMode = VK_POLYGON_MODE_LINE; VkPipelineMultisampleStateCreateInfo vkPipelineMultisampleStateCreateInfo; vkPipelineMultisampleStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; vkPipelineMultisampleStateCreateInfo.pNext = nullptr; vkPipelineMultisampleStateCreateInfo.flags = 0; vkPipelineMultisampleStateCreateInfo.rasterizationSamples = renderSampleCount; vkPipelineMultisampleStateCreateInfo.sampleShadingEnable = VK_FALSE; vkPipelineMultisampleStateCreateInfo.minSampleShading = 0.0f; vkPipelineMultisampleStateCreateInfo.pSampleMask = nullptr; vkPipelineMultisampleStateCreateInfo.alphaToCoverageEnable = VK_FALSE; vkPipelineMultisampleStateCreateInfo.alphaToOneEnable = VK_FALSE; // TODO Transparency VkPipelineColorBlendAttachmentState vkPipelineColorBlendAttachmentState[1]; vkPipelineColorBlendAttachmentState[0].blendEnable = VK_FALSE; vkPipelineColorBlendAttachmentState[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; vkPipelineColorBlendAttachmentState[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; vkPipelineColorBlendAttachmentState[0].colorBlendOp = VK_BLEND_OP_ADD; vkPipelineColorBlendAttachmentState[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; vkPipelineColorBlendAttachmentState[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; vkPipelineColorBlendAttachmentState[0].alphaBlendOp = VK_BLEND_OP_SUBTRACT; vkPipelineColorBlendAttachmentState[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; VkPipelineColorBlendStateCreateInfo vkPipelineColorBlendStateCreateInfo; vkPipelineColorBlendStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; vkPipelineColorBlendStateCreateInfo.pNext = nullptr; vkPipelineColorBlendStateCreateInfo.flags = {}; vkPipelineColorBlendStateCreateInfo.logicOpEnable = VK_FALSE; vkPipelineColorBlendStateCreateInfo.logicOp = VK_LOGIC_OP_COPY; vkPipelineColorBlendStateCreateInfo.attachmentCount = 1; vkPipelineColorBlendStateCreateInfo.pAttachments = vkPipelineColorBlendAttachmentState; vkPipelineColorBlendStateCreateInfo.blendConstants[0] = 0.0f; vkPipelineColorBlendStateCreateInfo.blendConstants[1] = 0.0f; vkPipelineColorBlendStateCreateInfo.blendConstants[2] = 0.0f; vkPipelineColorBlendStateCreateInfo.blendConstants[3] = 0.0f; VkDynamicState dynamicStates[2] = { VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_VIEWPORT }; VkPipelineDynamicStateCreateInfo vkPipelineDynamicStateCreateInfo; vkPipelineDynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; vkPipelineDynamicStateCreateInfo.pNext = nullptr; vkPipelineDynamicStateCreateInfo.flags = {}; vkPipelineDynamicStateCreateInfo.dynamicStateCount = 2; vkPipelineDynamicStateCreateInfo.pDynamicStates = dynamicStates; VkPipelineDepthStencilStateCreateInfo vkPipelineDepthStencilStateCreateInfo; vkPipelineDepthStencilStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; vkPipelineDepthStencilStateCreateInfo.pNext = nullptr; vkPipelineDepthStencilStateCreateInfo.flags = {}; vkPipelineDepthStencilStateCreateInfo.depthTestEnable = VK_TRUE; vkPipelineDepthStencilStateCreateInfo.depthWriteEnable = VK_TRUE; vkPipelineDepthStencilStateCreateInfo.depthCompareOp = VK_COMPARE_OP_LESS; vkPipelineDepthStencilStateCreateInfo.depthBoundsTestEnable = VK_FALSE; vkPipelineDepthStencilStateCreateInfo.stencilTestEnable = VK_FALSE; vkPipelineDepthStencilStateCreateInfo.front = {}; vkPipelineDepthStencilStateCreateInfo.back = {}; vkPipelineDepthStencilStateCreateInfo.minDepthBounds = {}; vkPipelineDepthStencilStateCreateInfo.maxDepthBounds = {}; AssetHandle vertShaderAssetHandle = AM_Register("assets/shaders/vert.vert.spv"); AssetHandle textureFragShaderAssetHandle = AM_Register("assets/shaders/texture.frag.spv"); const Asset *vertShaderAsset = AM_Get(vertShaderAssetHandle); const Asset *fragShaderAsset = AM_Get(textureFragShaderAssetHandle); VkShaderModuleCreateInfo vkShaderModuleCreateInfo[2]; vkShaderModuleCreateInfo[0].codeSize = vertShaderAsset->size; vkShaderModuleCreateInfo[0].pCode = reinterpret_cast(vertShaderAsset->ptr); vkShaderModuleCreateInfo[1].codeSize = fragShaderAsset->size; vkShaderModuleCreateInfo[1].pCode = reinterpret_cast(fragShaderAsset->ptr); VkShaderModule shaderModules[2]; VkPipelineShaderStageCreateInfo vkPipelineShaderStageCreateInfo[2]; for (long i = 0; i < 2; ++i) { vkShaderModuleCreateInfo[i].sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; vkShaderModuleCreateInfo[i].pNext = nullptr; vkShaderModuleCreateInfo[i].flags = {}; vkPipelineShaderStageCreateInfo[i].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; vkPipelineShaderStageCreateInfo[i].pNext = nullptr; vkPipelineShaderStageCreateInfo[i].flags = {}; vkPipelineShaderStageCreateInfo[i].pName = "main"; vkPipelineShaderStageCreateInfo[i].pSpecializationInfo = nullptr; vkCreateShaderModule(vkDevice, &vkShaderModuleCreateInfo[i], vkAllocator, &shaderModules[i]); } vkPipelineShaderStageCreateInfo[0].module = shaderModules[0]; vkPipelineShaderStageCreateInfo[1].module = shaderModules[1]; vkPipelineShaderStageCreateInfo[0].stage = VK_SHADER_STAGE_VERTEX_BIT; vkPipelineShaderStageCreateInfo[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; VkGraphicsPipelineCreateInfo vkGraphicsPipelineCreateInfo[2]; for (long i = 0; i < 2; ++i) { vkGraphicsPipelineCreateInfo[i].sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; vkGraphicsPipelineCreateInfo[i].pNext = nullptr; vkGraphicsPipelineCreateInfo[i].flags = {}; vkGraphicsPipelineCreateInfo[i].stageCount = 2; vkGraphicsPipelineCreateInfo[i].pStages = vkPipelineShaderStageCreateInfo; vkGraphicsPipelineCreateInfo[i].pVertexInputState = &vkPipelineVertexInputStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pInputAssemblyState = &vkPipelineInputAssemblyStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pTessellationState = nullptr; vkGraphicsPipelineCreateInfo[i].pViewportState = &vkPipelineViewportStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pMultisampleState = &vkPipelineMultisampleStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pDepthStencilState = &vkPipelineDepthStencilStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pColorBlendState = &vkPipelineColorBlendStateCreateInfo; vkGraphicsPipelineCreateInfo[i].pDynamicState = &vkPipelineDynamicStateCreateInfo; vkGraphicsPipelineCreateInfo[i].layout = vkPipelineLayout_Texture; vkGraphicsPipelineCreateInfo[i].renderPass = renderRenderPass; vkGraphicsPipelineCreateInfo[i].subpass = 0; vkGraphicsPipelineCreateInfo[i].basePipelineHandle = VK_NULL_HANDLE; vkGraphicsPipelineCreateInfo[i].basePipelineIndex = {}; } vkGraphicsPipelineCreateInfo[0].pRasterizationState = &vkPipelineRasterizationStateCreateInfoFill; vkGraphicsPipelineCreateInfo[1].pRasterizationState = &vkPipelineRasterizationStateCreateInfoLine; vkCreateGraphicsPipelines(vkDevice, VK_NULL_HANDLE, 2, vkGraphicsPipelineCreateInfo, vkAllocator, vkPipelines.pipelines); for (long i = 0; i < 2; ++i) { vkDestroyShaderModule(vkDevice, shaderModules[i], vkAllocator); } AM_Destroy(textureFragShaderAssetHandle); AM_Destroy(vertShaderAssetHandle); } long entityTypeCount = globalEntityTypes.Count(); for (long i = 0; i < entityTypeCount; ++i) { EntityType_Load(globalEntityTypes[i]); } } void EntityType_Load(EntityType &et) { assert(et.startingInstanceCount > 0); if (et.modelFile != nullptr && et.modelFile != CAFE_BABE(char)) { char modelPath[128]; memset(modelPath, '\0', 128); snprintf(modelPath, 128, "%s/%s", et.modelsDir, et.modelFile); AssetHandle assetHandle{AM_Register(modelPath)}; const Asset *asset = AM_Get(assetHandle); CompGrBinds &grBinds = ECS_CreateGrBinds(et.entityHandle); /* * 2023-09-13 - JCB * I don't like that we're just copying this. * This should be moved to window.cpp. */ grBinds.vkPipelineLayout = vkPipelineLayout_Texture; cgltf_options options{}; // TODO allocator cgltf_data *gltfData = nullptr; cgltf_result result = cgltf_parse(&options, asset->ptr, asset->size, &gltfData); assert(result == cgltf_result_success); result = cgltf_load_buffers(&options, gltfData, modelPath); assert(result == cgltf_result_success); result = cgltf_validate(gltfData); assert(result == cgltf_result_success); assert(gltfData->images_count < 2); if (gltfData->images_count == 1) { char imagePath[128]; memset(imagePath, '\0', 128); snprintf(imagePath, 128, "%s/%s", et.modelsDir, gltfData->images[0].uri); int pixelWidth, pixelHeight, pixelChannels; auto *pixels = stbi_load(imagePath, &pixelWidth, &pixelHeight, &pixelChannels, STBI_rgb_alpha); assert(pixels != nullptr && "sbti_load failed to load image."); uint32_t imageSizeBytes = pixelWidth * pixelHeight * pixelChannels; AssetHandle textureAssetHandle{AM_Register(pixels, imageSizeBytes, imagePath)}; VkFormat imageFormat = VK_FORMAT_R8G8B8A8_SRGB; if (pixelChannels == 3) { imageFormat = VK_FORMAT_R8G8B8_SRGB; } else if (pixelChannels == 2) { imageFormat = VK_FORMAT_R8G8_SRGB; } else if (pixelChannels == 1) { imageFormat = VK_FORMAT_R8_SRGB; } else { assert(pixelChannels != 0 && pixelChannels < 5); } VkImageCreateInfo vkImageCreateInfo; vkImageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; vkImageCreateInfo.pNext = nullptr; vkImageCreateInfo.flags = 0; vkImageCreateInfo.imageType = VK_IMAGE_TYPE_2D; vkImageCreateInfo.format = imageFormat; vkImageCreateInfo.extent = VkExtent3D { .width = static_cast(pixelWidth), .height = static_cast(pixelHeight), .depth = 1 }; vkImageCreateInfo.mipLevels = 1; vkImageCreateInfo.arrayLayers = 1; vkImageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; vkImageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; vkImageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; vkImageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; vkImageCreateInfo.queueFamilyIndexCount = 0; vkImageCreateInfo.pQueueFamilyIndices = nullptr; vkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; vkCreateImage(vkDevice, &vkImageCreateInfo, vkAllocator, &et.textureImage); VkMemoryRequirements imageMemReqs; vkGetImageMemoryRequirements(vkDevice, et.textureImage, &imageMemReqs); VkMemoryAllocateInfo imageAllocInfo; imageAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; imageAllocInfo.pNext = nullptr; imageAllocInfo.allocationSize = imageMemReqs.size; imageAllocInfo.memoryTypeIndex = FindMemoryTypeIndex(imageMemReqs.memoryTypeBits, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); if (imageAllocInfo.memoryTypeIndex == 0) { imageAllocInfo.memoryTypeIndex = FindMemoryTypeIndex(imageMemReqs.memoryTypeBits, 0); } vkAllocateMemory(vkDevice, &imageAllocInfo, vkAllocator, &et.deviceMemoryTexture); vkBindImageMemory(vkDevice, et.textureImage, et.deviceMemoryTexture, 0); VkImageViewCreateInfo vkImageViewCreateInfo; vkImageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; vkImageViewCreateInfo.pNext = nullptr; vkImageViewCreateInfo.flags = 0; vkImageViewCreateInfo.image = et.textureImage; // TODO animated textures vkImageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; vkImageViewCreateInfo.format = imageFormat; vkImageViewCreateInfo.components = VkComponentMapping { .r = VK_COMPONENT_SWIZZLE_IDENTITY, .g = VK_COMPONENT_SWIZZLE_IDENTITY, .b = VK_COMPONENT_SWIZZLE_IDENTITY, .a = VK_COMPONENT_SWIZZLE_IDENTITY, }; vkImageViewCreateInfo.subresourceRange = VkImageSubresourceRange { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, // TODO MapMap .levelCount = 1, .baseArrayLayer = 0, // TODO animated textures .layerCount = 1, }; vkCreateImageView(vkDevice, &vkImageViewCreateInfo, vkAllocator, &et.textureImageView); AM_Destroy(textureAssetHandle); // transition image layout and copy to buffer VkBuffer transferImageBuffer; VkDeviceMemory transferImageMemory; void *deviceData; BeginTransferBuffer(imageSizeBytes, transferImageBuffer, transferImageMemory, deviceData); memcpy(deviceData, gltfData->buffers[0].data, gltfData->buffers[0].size); { VkImageMemoryBarrier vkImageMemoryBarrier; vkImageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; vkImageMemoryBarrier.pNext = nullptr; vkImageMemoryBarrier.srcAccessMask = {}; vkImageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; vkImageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; vkImageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; vkImageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; vkImageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; vkImageMemoryBarrier.image = et.textureImage; vkImageMemoryBarrier.subresourceRange = VkImageSubresourceRange { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, // TODO MipMap .levelCount = 1, .baseArrayLayer = 0, // TODO animated textures .layerCount = 1, }; VkCommandBufferBeginInfo vkCommandBufferBeginInfo; vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; vkCommandBufferBeginInfo.pNext = nullptr; vkCommandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; vkCommandBufferBeginInfo.pInheritanceInfo = nullptr; vkBeginCommandBuffer(transferCommandBuffer, &vkCommandBufferBeginInfo); vkCmdPipelineBarrier(transferCommandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &vkImageMemoryBarrier); // TODO animated textures / texture array - make this an array VkBufferImageCopy vkBufferImageCopy; vkBufferImageCopy.bufferOffset = 0; vkBufferImageCopy.bufferRowLength = pixelWidth; vkBufferImageCopy.bufferImageHeight = pixelHeight; vkBufferImageCopy.imageSubresource = VkImageSubresourceLayers { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .mipLevel = 0, // TODO animated textures .baseArrayLayer = 0, .layerCount = 1, }; vkBufferImageCopy.imageOffset = VkOffset3D { .x = 0, .y = 0, .z = 0, }; vkBufferImageCopy.imageExtent = VkExtent3D { .width = static_cast(pixelWidth), .height = static_cast(pixelHeight), .depth = 1, }; vkCmdCopyBufferToImage(transferCommandBuffer, transferImageBuffer, et.textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &vkBufferImageCopy); vkEndCommandBuffer(transferCommandBuffer); VkSubmitInfo submitInfo; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.pNext = nullptr; submitInfo.waitSemaphoreCount = 0; submitInfo.pWaitSemaphores = nullptr; submitInfo.pWaitDstStageMask = nullptr; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &transferCommandBuffer; submitInfo.signalSemaphoreCount = 0; submitInfo.pSignalSemaphores = nullptr; vkQueueSubmit(transferQueue, 1, &submitInfo, nullptr); vkQueueWaitIdle(transferQueue); vkResetCommandBuffer(transferCommandBuffer, 0); } EndTransferBuffer(transferImageBuffer, transferImageMemory); { VkImageMemoryBarrier vkImageMemoryBarrier; vkImageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; vkImageMemoryBarrier.pNext = nullptr; vkImageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; vkImageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; vkImageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; vkImageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; vkImageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; vkImageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; vkImageMemoryBarrier.image = et.textureImage; vkImageMemoryBarrier.subresourceRange = VkImageSubresourceRange { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, // TODO MipMap .levelCount = 1, .baseArrayLayer = 0, // TODO animated textures .layerCount = 1, }; VkCommandBufferBeginInfo vkCommandBufferBeginInfo; vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; vkCommandBufferBeginInfo.pNext = nullptr; vkCommandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; vkCommandBufferBeginInfo.pInheritanceInfo = nullptr; vkBeginCommandBuffer(graphicsCommandBuffer, &vkCommandBufferBeginInfo); vkCmdPipelineBarrier(graphicsCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &vkImageMemoryBarrier); vkEndCommandBuffer(graphicsCommandBuffer); VkSubmitInfo submitInfo; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.pNext = nullptr; submitInfo.waitSemaphoreCount = 0; submitInfo.pWaitSemaphores = nullptr; submitInfo.pWaitDstStageMask = nullptr; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &graphicsCommandBuffer; submitInfo.signalSemaphoreCount = 0; submitInfo.pSignalSemaphores = nullptr; vkQueueSubmit(graphicsQueue, 1, &submitInfo, nullptr); vkQueueWaitIdle(graphicsQueue); } stbi_image_free(pixels); } // make sure cgltf can interpret our model for (long i = 0; i < gltfData->accessors_count; ++i) { assert(gltfData->accessors[i].type != cgltf_type_invalid); } for (long i = 0; i < gltfData->buffers_count; ++i) { assert(gltfData->buffer_views[i].type != cgltf_buffer_view_type_invalid); } assert(et.Importer_GLTF.AccessorIndexVertex > -1); VkBufferCreateInfo bufferCI; bufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferCI.pNext = nullptr; bufferCI.flags = {}; bufferCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; bufferCI.queueFamilyIndexCount = 1; bufferCI.pQueueFamilyIndices = &graphicsFamilyIndex; VkMemoryRequirements vkMemoryRequirements[4]; long index = 0; if (et.Importer_GLTF.AccessorIndexVertex > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexVertex]; grBinds.vertexCount = acc.count; bufferCI.size = acc.buffer_view->size; bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &grBinds.vertexBuffer); vkGetBufferMemoryRequirements(vkDevice, grBinds.vertexBuffer, &vkMemoryRequirements[index++]); } if (et.Importer_GLTF.AccessorIndexNormal > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexNormal]; grBinds.normalsCount = acc.count; bufferCI.size = acc.buffer_view->size; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &grBinds.normalsBuffer); vkGetBufferMemoryRequirements(vkDevice, grBinds.normalsBuffer, &vkMemoryRequirements[index++]); } if (et.Importer_GLTF.AccessorIndexUV > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexUV]; grBinds.uvCount = acc.count; bufferCI.size = acc.buffer_view->size; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &grBinds.uvBuffer); vkGetBufferMemoryRequirements(vkDevice, grBinds.uvBuffer, &vkMemoryRequirements[index++]); } if (et.Importer_GLTF.AccessorIndexIndex > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexIndex]; grBinds.indexCount = acc.count; bufferCI.size = acc.buffer_view->size; bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &grBinds.indexBuffer); vkGetBufferMemoryRequirements(vkDevice, grBinds.indexBuffer, &vkMemoryRequirements[index++]); } VkMemoryRequirements combinedMemReqs{}; combinedMemReqs.alignment = vkMemoryRequirements[0].alignment; combinedMemReqs.memoryTypeBits = 0; combinedMemReqs.size = 0; for (long i = 1; i < index; ++i) { if (combinedMemReqs.alignment == vkMemoryRequirements[i].alignment) { continue; } int larger, smaller; if (combinedMemReqs.alignment > vkMemoryRequirements[i].alignment) { larger = combinedMemReqs.alignment; smaller = vkMemoryRequirements[i].alignment; } else { larger = vkMemoryRequirements[i].alignment; smaller = combinedMemReqs.alignment; } if (larger % smaller == 0) { combinedMemReqs.alignment = larger; continue; } int combined = larger * smaller; while ((combined / 2) % larger == 0) { combined /= 2; } } for (long i = 0; i < index; ++i) { uint32_t alignmentPadding = vkMemoryRequirements[i].size % combinedMemReqs.alignment; alignmentPadding = combinedMemReqs.alignment - alignmentPadding; combinedMemReqs.size += vkMemoryRequirements[i].size + alignmentPadding; combinedMemReqs.memoryTypeBits |= vkMemoryRequirements[i].memoryTypeBits; } // create VkDeviceMemory VkMemoryAllocateInfo vkMemoryAllocateInfo; vkMemoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; vkMemoryAllocateInfo.pNext = nullptr; vkMemoryAllocateInfo.allocationSize = combinedMemReqs.size; vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(combinedMemReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &et.deviceMemoryVert); // bind buffers uint32_t runningOffset = 0; if (et.Importer_GLTF.AccessorIndexVertex > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexVertex]; vkBindBufferMemory(vkDevice, grBinds.vertexBuffer, et.deviceMemoryVert, runningOffset); runningOffset += acc.buffer_view->size; runningOffset += combinedMemReqs.alignment - (runningOffset % combinedMemReqs.alignment); } if (et.Importer_GLTF.AccessorIndexNormal > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexNormal]; vkBindBufferMemory(vkDevice, grBinds.normalsBuffer, et.deviceMemoryVert, runningOffset); runningOffset += acc.buffer_view->size; runningOffset += combinedMemReqs.alignment - (runningOffset % combinedMemReqs.alignment); } if (et.Importer_GLTF.AccessorIndexUV > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexUV]; vkBindBufferMemory(vkDevice, grBinds.uvBuffer , et.deviceMemoryVert, runningOffset); runningOffset += acc.buffer_view->size; runningOffset += combinedMemReqs.alignment - (runningOffset % combinedMemReqs.alignment); } if (et.Importer_GLTF.AccessorIndexIndex > -1) { // const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexIndex]; vkBindBufferMemory(vkDevice, grBinds.indexBuffer, et.deviceMemoryVert, runningOffset); } // create transfer items && transfer { VkDeviceMemory transferDeviceMemory; VkBuffer transferBuffer; void *data; BeginTransferBuffer(combinedMemReqs.size, transferBuffer, transferDeviceMemory, data); uint32_t runningOffset2 = 0; if (et.Importer_GLTF.AccessorIndexVertex > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexVertex]; char *dstPtr = static_cast(data) + runningOffset2; char *srcPtr = static_cast(gltfData->buffers[0].data) + acc.buffer_view->offset; memcpy(dstPtr, srcPtr, acc.buffer_view->size); runningOffset2 += acc.buffer_view->size; } if (et.Importer_GLTF.AccessorIndexNormal > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexNormal]; char *dstPtr = static_cast(data) + runningOffset2; char *srcPtr = static_cast(gltfData->buffers[0].data) + acc.buffer_view->offset; memcpy(dstPtr, srcPtr, acc.buffer_view->size); runningOffset2 += acc.buffer_view->size; } if (et.Importer_GLTF.AccessorIndexUV > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexUV]; char *dstPtr = static_cast(data) + runningOffset2; char *srcPtr = static_cast(gltfData->buffers[0].data) + acc.buffer_view->offset; memcpy(dstPtr, srcPtr, acc.buffer_view->size); runningOffset2 += acc.buffer_view->size; } if (et.Importer_GLTF.AccessorIndexIndex > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexIndex]; char *dstPtr = static_cast(data) + runningOffset2; char *srcPtr = static_cast(gltfData->buffers[0].data) + acc.buffer_view->offset; memcpy(dstPtr, srcPtr, acc.buffer_view->size); } VkCommandBufferBeginInfo vkCommandBufferBeginInfo; vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; vkCommandBufferBeginInfo.pNext = nullptr; // TODO consider single-use? vkCommandBufferBeginInfo.flags = 0; vkCommandBufferBeginInfo.pInheritanceInfo = nullptr; vkBeginCommandBuffer(transferCommandBuffer, &vkCommandBufferBeginInfo); VkBufferCopy bufferCopys[4]; for (long i = 0; i < 4; ++i) { bufferCopys[i].dstOffset = 0; } index = 0; if (et.Importer_GLTF.AccessorIndexVertex > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexVertex]; bufferCopys[index].srcOffset = acc.buffer_view->offset; bufferCopys[index].size = acc.buffer_view->size; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, grBinds.vertexBuffer, 1, &bufferCopys[index]); index += 1; } if (et.Importer_GLTF.AccessorIndexNormal > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexNormal]; bufferCopys[index].srcOffset = acc.buffer_view->offset; bufferCopys[index].size = acc.buffer_view->size; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, grBinds.normalsBuffer, 1, &bufferCopys[index]); index += 1; } if (et.Importer_GLTF.AccessorIndexUV > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexUV]; bufferCopys[index].srcOffset = acc.buffer_view->offset; bufferCopys[index].size = acc.buffer_view->size; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, grBinds.uvBuffer, 1, &bufferCopys[index]); index += 1; } if (et.Importer_GLTF.AccessorIndexIndex > -1) { const auto &acc = gltfData->accessors[et.Importer_GLTF.AccessorIndexIndex]; bufferCopys[index].srcOffset = acc.buffer_view->offset; bufferCopys[index].size = acc.buffer_view->size; vkCmdCopyBuffer(transferCommandBuffer, transferBuffer, grBinds.indexBuffer, 1, &bufferCopys[index]); } vkEndCommandBuffer(transferCommandBuffer); VkSubmitInfo submitInfo; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.pNext = nullptr; submitInfo.waitSemaphoreCount = 0; submitInfo.pWaitSemaphores = nullptr; submitInfo.pWaitDstStageMask = nullptr; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &transferCommandBuffer; submitInfo.signalSemaphoreCount = 0; submitInfo.pSignalSemaphores = nullptr; vkQueueSubmit(transferQueue, 1, &submitInfo, nullptr); vkQueueWaitIdle(transferQueue); EndTransferBuffer(transferBuffer, transferDeviceMemory); } // set up instance buffer bufferCI.size = sizeof(InstPos) * et.startingInstanceCount; bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; vkCreateBuffer(vkDevice, &bufferCI, vkAllocator, &grBinds.instanceBuffer); VkMemoryRequirements vkMemoryRequirementsInst; vkGetBufferMemoryRequirements(vkDevice, grBinds.instanceBuffer, &vkMemoryRequirementsInst); vkMemoryAllocateInfo.allocationSize = vkMemoryRequirementsInst.size; vkMemoryAllocateInfo.memoryTypeIndex = FindMemoryTypeIndex(vkMemoryRequirementsInst.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); vkAllocateMemory(vkDevice, &vkMemoryAllocateInfo, vkAllocator, &et.deviceMemoryInst); vkBindBufferMemory(vkDevice, grBinds.instanceBuffer, et.deviceMemoryInst, 0); // cleanup cgltf_free(gltfData); AM_Destroy(assetHandle); } } void EntityType_Teardown() { long entityTypeCount = globalEntityTypes.Count(); for (long i = 0; i < entityTypeCount; ++i) { if (globalEntityTypes[i].modelFile == nullptr) continue; auto *et = &globalEntityTypes[i]; auto *grBinds = ECS_GetGrBinds(globalEntityTypes[i].entityHandle); if (grBinds->vertexBuffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->vertexBuffer, vkAllocator); if (grBinds->normalsBuffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->normalsBuffer, vkAllocator); if (grBinds->uvBuffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->uvBuffer, vkAllocator); if (grBinds->indexBuffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->indexBuffer, vkAllocator); if (grBinds->instanceBuffer != VK_NULL_HANDLE) vkDestroyBuffer(vkDevice, grBinds->instanceBuffer, vkAllocator); if (et->textureImageView != VK_NULL_HANDLE) vkDestroyImageView(vkDevice, et->textureImageView, vkAllocator); if (et->textureImage != VK_NULL_HANDLE) vkDestroyImage(vkDevice, et->textureImage, vkAllocator); if (et->deviceMemoryInst != VK_NULL_HANDLE) vkFreeMemory(vkDevice, et->deviceMemoryInst, vkAllocator); if (et->deviceMemoryVert != VK_NULL_HANDLE) vkFreeMemory(vkDevice, et->deviceMemoryVert, vkAllocator); if (et->deviceMemoryTexture != VK_NULL_HANDLE) vkFreeMemory(vkDevice, et->deviceMemoryTexture, vkAllocator); } if (vkSampler_Texture != VK_NULL_HANDLE) vkDestroySampler(vkDevice, vkSampler_Texture, vkAllocator); for (long i = 0; i < 2; ++i) { if (vkPipelines.pipelines[i] != VK_NULL_HANDLE) vkDestroyPipeline(vkDevice, vkPipelines.pipelines[i], vkAllocator); } if (vkPipelineLayout_Texture != VK_NULL_HANDLE) vkDestroyPipelineLayout(vkDevice, vkPipelineLayout_Texture, vkAllocator); if (vkDescriptorSetLayout_Texture != VK_NULL_HANDLE) vkDestroyDescriptorSetLayout(vkDevice, vkDescriptorSetLayout_Texture, vkAllocator); }