#pragma once

#include "memblock.h"
#include "matrix.h"
#include "linmtrx.h"

//~~~~~~~~~~~~~~~~~~~~~~~ AffineMatrixStack ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class AffineMatrixStack:
	public MemoryStack
{
 public:
	AffineMatrixStack(
		size_t start,
		size_t delta
	):
		MemoryStack(sizeof(AffineMatrix),start,delta)
			{}

	AffineMatrix*
		Peek()
			{
				Check(this);
				return Cast_Object(AffineMatrix*,MemoryStack::Peek());
			}

	AffineMatrixStack&
		Concatenate(const AffineMatrix& matrix);
	AffineMatrixStack&
		operator*=(const AffineMatrix& matrix)
			{Check(this); Check(&matrix); return Concatenate(matrix);}

	AffineMatrix&
		Push(const AffineMatrix& matrix)
			{
				Check(this); Check(&matrix);
				return *Cast_Object(AffineMatrix*,MemoryStack::Push(&matrix));
			}

	operator AffineMatrix&()
		{Check(this); return *Peek();}
};

//~~~~~~~~~~~~~~~~~~~~~~~ LinearMatrixStack ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class LinearMatrixStack:
	public MemoryStack
{
 public:
	LinearMatrixStack(
		size_t start,
		size_t delta
	):
		MemoryStack(sizeof(LinearMatrix),start,delta)
			{}

	LinearMatrix*
		Peek()
			{
				Check(this);
				return Cast_Object(LinearMatrix*,MemoryStack::Peek());
			}

	LinearMatrixStack&
		Concatenate(const LinearMatrix& matrix);
	LinearMatrixStack&
		operator*=(const LinearMatrix& matrix)
			{Check(this); Check(&matrix); return Concatenate(matrix);}

	LinearMatrix&
		Push(const LinearMatrix& matrix)
			{
				Check(this); Check(&matrix);
				return *Cast_Object(LinearMatrix*,MemoryStack::Push(&matrix));
			}

	operator LinearMatrix&()
		{Check(this); return *Peek();}
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~ Matrix4x4Stack ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class Matrix4x4Stack:
	public MemoryStack
{
 public:
	Matrix4x4Stack(
		size_t start,
		size_t delta
	):
		MemoryStack(sizeof(Matrix4x4),start,delta)
			{}

	Matrix4x4*
		Peek()
			{
				Check(this);
				return Cast_Object(Matrix4x4*,MemoryStack::Peek());
			}

	Matrix4x4Stack&
		Concatenate(const Matrix4x4& matrix);
	Matrix4x4Stack&
		Concatenate(const AffineMatrix& matrix);
	Matrix4x4Stack&
		operator*=(const Matrix4x4& matrix)
			{Check(this); Check(&matrix); return Concatenate(matrix);}
	Matrix4x4Stack&
		operator*=(const AffineMatrix& matrix)
			{Check(this); Check(&matrix); return Concatenate(matrix);}

	Matrix4x4&
		Push(const Matrix4x4& matrix)
			{
				Check(this); Check(&matrix);
				return *Cast_Object(Matrix4x4*,MemoryStack::Push(&matrix));
			}
	Matrix4x4&
		Push(const AffineMatrix& matrix);

	operator Matrix4x4&()
		{Check(this); return *Peek();}
};
