#ifndef VEC2_H
#define VEC2_H


#define _CREATE_DECLARATION(_NAME, _TYPE)				\
struct _NAME {								\
	_TYPE x, y;							\
};									\
									\
struct _NAME _NAME(_TYPE x, _TYPE y);					\
struct _NAME _NAME##s(_TYPE x);					\
									\
struct _NAME _NAME##_add(struct _NAME a, struct _NAME b);		\
struct _NAME _NAME##_sub(struct _NAME a, struct _NAME b);		\
struct _NAME _NAME##_mul(struct _NAME a, struct _NAME b);		\
struct _NAME _NAME##_mul3(struct _NAME a, struct _NAME b, struct _NAME c);	\
struct _NAME _NAME##_mul4(struct _NAME a, struct _NAME b,		\
			  struct _NAME c, struct _NAME d);		\
struct _NAME _NAME##_div(struct _NAME a, struct _NAME b);

_CREATE_DECLARATION(vec2, double)
_CREATE_DECLARATION(vec2f, float)

struct vec2f vec2_to_f(struct vec2 a);

_CREATE_DECLARATION(vec2i, int32_t)
_CREATE_DECLARATION(vec2i64, int64_t)
_CREATE_DECLARATION(vec2ui, uint32_t)

struct vec2f vec2f_from_ui(struct vec2ui a);

#undef _CREATE_DECLARATION

#if defined(VEC2_IMP) || defined(IMP)

#define _CREATE_DEFINITION(_NAME, _TYPE)			\
struct _NAME								\
_NAME(_TYPE x, _TYPE y) {						\
	return (struct _NAME) {.x = x, .y = y};				\
}									\
									\
struct _NAME								\
_NAME##s(_TYPE x) {							\
	return (struct _NAME) {.x = x, .y = x};			\
}									\
									\
struct _NAME								\
_NAME##_add(struct _NAME a, struct _NAME b)				\
{									\
	return (struct _NAME){.x = a.x + b.x, .y = a.y + b.y};		\
}									\
									\
struct _NAME								\
_NAME##_sub(struct _NAME a, struct _NAME b)				\
{									\
	return (struct _NAME){.x = a.x - b.x, .y = a.y - b.y};		\
}									\
									\
struct _NAME								\
_NAME##_mul(struct _NAME a, struct _NAME b)				\
{									\
	return (struct _NAME){.x = a.x * b.x, .y = a.y * b.y};		\
}									\
									\
struct _NAME								\
_NAME##_mul3(struct _NAME a, struct _NAME b, struct _NAME c)		\
{									\
	return _NAME##_mul(_NAME##_mul(a, b), c);			\
}									\
									\
struct _NAME								\
_NAME##_mul4(struct _NAME a, struct _NAME b, struct _NAME c, struct _NAME d) \
{									\
	return _NAME##_mul(_NAME##_mul3(a, b, c), d);			\
}									\
									\
struct _NAME								\
_NAME##_div(struct _NAME a, struct _NAME b)				\
{									\
	return (struct _NAME){.x = a.x / b.x, .y = a.y / b.y};		\
}

_CREATE_DEFINITION(vec2, double)
_CREATE_DEFINITION(vec2f, float)

struct vec2f
vec2f_from_ui(struct vec2ui a)
{
	return (struct vec2f) { .x = (float) a.x, .y = (float) a.y };
}

struct vec2f
vec2_to_f(struct vec2 a)
{
	return (struct vec2f) { .x= (float) a.x, .y= (float) a.y };
}


_CREATE_DEFINITION(vec2i, int32_t)
_CREATE_DEFINITION(vec2i64, int64_t)
_CREATE_DEFINITION(vec2ui, uint32_t)

#undef _CREATE_DEFINITION

#endif /* defined(VEC2_IMP) || defined(IMP) */

#endif	/* VEC2_H */
