#include "stdafx.h"
#include "VertexDesc.h"

namespace gui {

	VertexDesc::VertexDesc(Nat totalSize)
		: elemSize(totalSize),
		  data(runtime::allocArray<Elem>(engine(), &dataType, 2)) {}

	VertexDesc::VertexDesc(const VertexDesc &o)
		: elemSize(o.elemSize),
		  data(runtime::allocArray<Elem>(engine(), &dataType, o.data->count())) {
		memcpy(data->v, o.data->v, sizeof(Elem) * o.data->filled);
		data->filled = o.data->filled;
	}

	void VertexDesc::add(Nat offset, Bool integer, Nat components) {
		if (data->filled >= data->count()) {
			GcArray<Elem> *updated = runtime::allocArray<Elem>(engine(), &dataType, data->count() * 2);
			memcpy(updated->v, data->v, sizeof(Elem) * data->filled);
			updated->filled = data->filled;
			data = updated;
		}

		Nat identifier = 0;
		if (data->filled > 0) {
			const Elem &last = data->v[data->filled - 1];
			identifier = last.identifier + (last.components + 3) / 4;
		}
		data->v[data->filled++] = Elem(0, offset, identifier, integer, components);
	}

	void VertexDesc::append(VertexDesc *from, Nat slot) {
		GcArray<Elem> *updated = runtime::allocArray<Elem>(engine(), &dataType, data->filled + from->data->filled);
		memcpy(updated->v, data->v, sizeof(Elem) * data->filled);
		updated->filled = data->filled;
		data = updated;

		// Figure out the proper offset for identifiers:
		Nat idOffset = 0;
		if (data->filled > 0) {
			const Elem &last = data->v[data->filled - 1];
			idOffset = last.identifier + (last.components + 3) / 4;
		}

		// Copy and update:
		for (size_t i = 0; i < from->data->filled; i++) {
			size_t to = data->filled++;
			data->v[to] = from->data->v[i];

			data->v[to].slot = slot;
			data->v[to].identifier += idOffset;
		}
	}

	void VertexDesc::toS(StrBuf *to) const {
		for (Nat i = 0; i < count(); i++) {
			if (i > 0)
				*to << S("\n");
			data->v[i].toS(to);
		}
	}

	const GcType VertexDesc::dataType = {
		GcType::tArray,
		null,
		null,
		sizeof(Elem),
		1,
		{ OFFSET_OF(Elem, identifier) }
	};


	void VertexDesc::Elem::toS(StrBuf *to) const {
		*to << S("@") << offset << S(": ") << identifier
			<< S(", ") << (integer ? S("int") : S("float"))
			<< S(", ") << components;
	}

}
