/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#include "LabelDrawableVulkanEncoder.hpp"
#include "Scene/TextDrawable.hpp"
#include "Scene/DrawEncoder.hpp"
#include "VulkanGeometry.hpp"
#include "Vulkan/Scene/VulkanTexture.hpp"
#include "Vulkan/Scene/VulkanUniformBuffer.hpp"
#include "Vulkan/Scene/VulkanVertexBuffer.hpp"

using namespace OpenVulkano::Scene;

namespace OpenVulkano::Vulkan
{
	void EncodeBackground(LabelDrawable* labelDrawable, VulkanDrawContext* drawContext)
	{
		VulkanUniformBuffer* vkBuffer = labelDrawable->GetLabelBuffer()->GetRenderResource();
		if (!vkBuffer) vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(labelDrawable->GetLabelBuffer());
		vkBuffer->Record(drawContext);

		for (Node* node: labelDrawable->GetNodes())
		{
			if (!node->IsEnabled()) [[unlikely]] continue;
			drawContext->EncodeNode(node);
		}
		drawContext->commandBuffer.draw(4, 1, 0, 0);
	}

	void EncodeTextDrawable(LabelDrawable* labelDrawable, VulkanDrawContext* drawContext)
	{
		for (TextDrawable& entry : labelDrawable->GetTexts())
		{
			drawContext->EncodeShader(entry.GetShader());
			VertexBuffer* vbo = entry.GetVertexBuffer();
			VulkanVertexBuffer* renderVbo = vbo->GetRenderResource();
			if (!renderVbo) renderVbo = drawContext->renderer->GetResourceManager().PrepareVertexBuffer(vbo);
			renderVbo->RecordBind(drawContext->commandBuffer);

			if (labelDrawable->IsBillboard())
			{
				VulkanUniformBuffer* vkBuffer = labelDrawable->GetLabelBuffer()->GetRenderResource();
				if (!vkBuffer) vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(labelDrawable->GetLabelBuffer());
				vkBuffer->Record(drawContext);
			}

			VulkanTexture* renderTexture = entry.GetTexture()->GetRenderResource();
			if (!renderTexture)
			{
				renderTexture = drawContext->renderer->GetResourceManager().PrepareTexture(entry.GetTexture());
			}
			renderTexture->Record(drawContext);
		
			for (Node* node: labelDrawable->GetNodes())
			{
				if (!node->IsEnabled()) [[unlikely]] continue;
				drawContext->EncodeNode(node);
				drawContext->commandBuffer.draw(4, entry.GetSymbolCount(), 0, 0);
			}
		}
	}

	void EncodeLabelDrawable(Drawable* instance, VulkanDrawContext* drawContext)
	{
		LabelDrawable* labelDrawable = static_cast<LabelDrawable*>(instance);
		EncodeBackground(labelDrawable, drawContext);
		EncodeTextDrawable(labelDrawable, drawContext);
	}
}

namespace
{
	[[maybe_unused]] void* labelDrawableVulkanEncoderReg = DrawEncoder::RegisterVulkanEncodeFunction<LabelDrawable>(&OpenVulkano::Vulkan::EncodeLabelDrawable);
}