text: #pragma once
  #include "OpenGL.h"
  #include <vector>
  
  
  namespace dae
  {
  	class BufferElement
  	{
  	public:
  
  		BufferElement() = default;
  		std::string Name = "";
  		uint32_t Offset = 0;
  		uint32_t Size = 0;
  		ShaderDataType Type = ShaderDataType::Bool;
  		bool Normalized = false;
  
  
  		BufferElement( ShaderDataType type, const std::string& name)
  			: Name(name), Type(type), Size(ShaderDataTypeSize(type)), Offset(0), Normalized(false) {}
  	
  
  		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;
  
  
  			}
  
  		}
  		uint32_t 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;
  			case ShaderDataType::Mat4:		return 4*4;
  			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;
  			default:						return 1;
  			}
  
  
  		}
  
  	};
  
  
  	class BufferLayout
  	{
  	public:
  
  		BufferLayout() {}
  
  		BufferLayout(const std::initializer_list<BufferElement>& element)
  			: m_Elements(element) {
  			CalculateOffsetAndStride();
  		}
  
  
  		std::vector<BufferElement>::iterator begin() { return m_Elements.begin(); }
  		std::vector<BufferElement>::iterator end() { return m_Elements.end(); }
  		std::vector<BufferElement>::const_iterator begin() const { return m_Elements.begin(); }
  		std::vector<BufferElement>::const_iterator end() const { return m_Elements.end(); }
  
  
  		inline uint32_t GetStride() const { return m_Stride; }
  		inline const std::vector<BufferElement> GetElements() const { return m_Elements; }
  	private:
  		void CalculateOffsetAndStride()
  		{
  			uint32_t offset = 0;
  			m_Stride = 0;
  
  
  			for (auto& element : m_Elements)
  			{
  				element.Offset = offset;
  				offset += element.Size;
  				m_Stride += element.Size;
  			}
  		}
  
  		std::vector<BufferElement> m_Elements;
  		uint32_t m_Stride = 0;
  
  
  	};
  
  
  }
  