#pragma once

#include <cstddef>
#include <cstring>
#include <vector>

inline std::size_t AlignStd140(std::size_t offset, std::size_t alignment)
{
	const std::size_t mask = alignment - 1;
	return (offset + mask) & ~mask;
}

template <typename TValue>
inline void AppendStd140Value(std::vector<unsigned char>& buffer, std::size_t alignment, const TValue& value)
{
	const std::size_t offset = AlignStd140(buffer.size(), alignment);
	if (buffer.size() < offset + sizeof(TValue))
		buffer.resize(offset + sizeof(TValue), 0);
	std::memcpy(buffer.data() + offset, &value, sizeof(TValue));
}

inline void AppendStd140Float(std::vector<unsigned char>& buffer, float value)
{
	AppendStd140Value(buffer, 4, value);
}

inline void AppendStd140Int(std::vector<unsigned char>& buffer, int value)
{
	AppendStd140Value(buffer, 4, value);
}

inline void AppendStd140Vec2(std::vector<unsigned char>& buffer, float x, float y)
{
	const std::size_t offset = AlignStd140(buffer.size(), 8);
	if (buffer.size() < offset + sizeof(float) * 2)
		buffer.resize(offset + sizeof(float) * 2, 0);
	float values[2] = { x, y };
	std::memcpy(buffer.data() + offset, values, sizeof(values));
}

inline void AppendStd140Vec4(std::vector<unsigned char>& buffer, float x, float y, float z, float w)
{
	const std::size_t offset = AlignStd140(buffer.size(), 16);
	if (buffer.size() < offset + sizeof(float) * 4)
		buffer.resize(offset + sizeof(float) * 4, 0);
	float values[4] = { x, y, z, w };
	std::memcpy(buffer.data() + offset, values, sizeof(values));
}
