#include <pch.hpp>

#include <core.hpp>
#include <opengl/opengl_buffer.hpp>
#include <renderer/renderer.hpp>
#include <renderer/buffer.hpp>

#include <cstdint>

namespace OpenEngine {

	uint32_t shaderDataTypeSize(ShaderDataType type)
	{
		switch (type)
		{
			case ShaderDataType::Float: return 4;
			case ShaderDataType::Float2: return 4 * 2;
			case ShaderDataType::Float3: return 4 * 3;
			case ShaderDataType::Float4: return 4 * 4;
			case ShaderDataType::Mat3: return 4 * 3 * 3;
			case ShaderDataType::Mat4: return 4 * 4 * 4;
			case ShaderDataType::Int: return 4;
			case ShaderDataType::Int2: return 4 * 2;
			case ShaderDataType::Int3: return 4 * 3;
			case ShaderDataType::Int4: return 4 * 4;
			case ShaderDataType::Bool: return 1;
		}

		OE_CORE_ASSERT(false, "Unknown ShaderDataType!");
		return 0;
	}

    uint32_t BufferLayoutElement::GetComponentCount() const
    {
        switch (type)
        {
            case ShaderDataType::Float: return 1;
            case ShaderDataType::Float2: return 2;
            case ShaderDataType::Float3: return 3;
            case ShaderDataType::Float4: return 4;
            case ShaderDataType::Mat3: return 3; // * 3 float3;
            case ShaderDataType::Mat4: return 4; // * 4 float4;
            case ShaderDataType::Int: return 1;
            case ShaderDataType::Int2: return 2;
            case ShaderDataType::Int3: return 3;
            case ShaderDataType::Int4: return 4;
            case ShaderDataType::Bool: return 1;
        }

        OE_CORE_ASSERT(false, "Unknown ShaderDataType!");
        return 0;
    }

    void BufferLayout::CalculateOffsetsAndStride()
    {
        OE_PROFILE_FUNCTION();

        uint32_t offset = 0;
        stride = 0;
        for (auto& element : elements)
        {
            element.offset = offset;
            offset += element.size;
            stride += element.size;
        }
    }

    Ref<VertexBuffer> VertexBuffer::Create(uint32_t size)
    {
        OE_PROFILE_FUNCTION();

        switch (Renderer::GetAPI()) {
            case RendererAPI::API::None : OE_CORE_ASSERT(false, "No render API selected!"); return nullptr;
            case RendererAPI::API::OpenGL : return CreateRef<OpenGLVertexBuffer>(size);
        }

        OE_CORE_ASSERT(false, "Selected API not supported");
        return nullptr;
    }

    Ref<VertexBuffer> VertexBuffer::Create(float* vertices, uint32_t size)
    {
        OE_PROFILE_FUNCTION();

        switch (Renderer::GetAPI()) {
            case RendererAPI::API::None : OE_CORE_ASSERT(false, "No render API selected!"); return nullptr;
            case RendererAPI::API::OpenGL : return CreateRef<OpenGLVertexBuffer>(vertices, size);
        }

        OE_CORE_ASSERT(false, "Selected API not supported");
        return nullptr;
    }

    Ref<IndexBuffer> IndexBuffer::Create(uint32_t* indices, uint32_t count)
    {
        OE_PROFILE_FUNCTION();

        switch (Renderer::GetAPI()) {
            case RendererAPI::API::None : OE_CORE_ASSERT(false, "No render API selected!"); return nullptr;
            case RendererAPI::API::OpenGL : return CreateRef<OpenGLIndexBuffer>(indices, count);
        }

        OE_CORE_ASSERT(false, "Selected API not supported");
        return nullptr;
    }
}
