﻿#include "DVKVertexBuffer.h"

namespace vk_demo
{
	
	DVKVertexBuffer* DVKVertexBuffer::Create(std::shared_ptr<VulkanDevice> vulkanDevice, DVKCommandBuffer* cmdBuffer, std::vector<float> vertices, const std::vector<VertexAttribute>& attributes)
	{
		VkDevice device = vulkanDevice->GetInstanceHandle();

		DVKVertexBuffer* vertexBuffer = new DVKVertexBuffer();
		vertexBuffer->device	 = device;
		vertexBuffer->attributes = attributes;

		vk_demo::DVKBuffer* vertexStaging = vk_demo::DVKBuffer::CreateBuffer(
			vulkanDevice, 
			VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 
			VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 
			vertices.size() * sizeof(float), 
			vertices.data()
		);

		vertexBuffer->dvkBuffer = vk_demo::DVKBuffer::CreateBuffer(
			vulkanDevice, 
			VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, 
			VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 
			vertices.size() * sizeof(float)
		);

		cmdBuffer->Begin();

		VkBufferCopy copyRegion = {};
		copyRegion.size = vertices.size() * sizeof(float);
		vkCmdCopyBuffer(cmdBuffer->cmdBuffer, vertexStaging->buffer, vertexBuffer->dvkBuffer->buffer, 1, &copyRegion);

		cmdBuffer->End();
		cmdBuffer->Submit();

		delete vertexStaging;

		return vertexBuffer;
	}

	std::vector<VkVertexInputAttributeDescription> DVKVertexBuffer::GetInputAttributes(const std::vector<VertexAttribute>& shaderInputs)
	{
		std::vector<VkVertexInputAttributeDescription> vertexInputAttributs;
		int32 offset = 0;
		for (int32 i = 0; i < shaderInputs.size(); ++i)
		{
			VkVertexInputAttributeDescription inputAttribute = {};
			inputAttribute.binding  = 0;
			inputAttribute.location = i;
			inputAttribute.format   = VertexAttributeToVkFormat(shaderInputs[i]);
			inputAttribute.offset   = offset;
			offset += VertexAttributeToSize(shaderInputs[i]);
			vertexInputAttributs.push_back(inputAttribute);
		}
		return vertexInputAttributs;
	}

	VkVertexInputBindingDescription DVKVertexBuffer::GetInputBinding()
	{
		int32 stride = 0;
		for (int32 i = 0; i < attributes.size(); ++i) {
			stride += VertexAttributeToSize(attributes[i]);
		}

		VkVertexInputBindingDescription vertexInputBinding = {};
		vertexInputBinding.binding   = 0;
		vertexInputBinding.stride    = stride;
		vertexInputBinding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;

		return vertexInputBinding;
	}

};